<!DOCTYPE html>


  <html class="dark page-post">


<head><meta name="generator" content="Hexo 3.9.0">
  <meta charset="utf-8">
  
  <title>Typescript实践总结[基础+工程+实践] | Poetry&#39;s Blog</title>

  <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1">

  
    <meta name="keywords" content="JavaScript,Typescript,">
  

  <meta name="description" content="第一章 基础篇 TS基础篇   一、基本类型 JavaScript 的类型分为两种：原始数据类型和对象类型。 原始数据类型包括：布尔值、数值、字符串、null、undefined 以及 ES6 中的新类型 Symbol 本节主要介绍前五种原始数据类型在 TypeScript 中的应用。 布尔值是最基础的数据类型，在 TypeScript 中，使用 boolean 定义布尔值类型  ES6数据类型">
<meta name="keywords" content="JavaScript,Typescript">
<meta property="og:type" content="article">
<meta property="og:title" content="Typescript实践总结[基础+工程+实践]">
<meta property="og:url" content="http://blog.poetries.top/2019/09/03/ts-in-action/index.html">
<meta property="og:site_name" content="Poetry&#39;s Blog">
<meta property="og:description" content="第一章 基础篇 TS基础篇   一、基本类型 JavaScript 的类型分为两种：原始数据类型和对象类型。 原始数据类型包括：布尔值、数值、字符串、null、undefined 以及 ES6 中的新类型 Symbol 本节主要介绍前五种原始数据类型在 TypeScript 中的应用。 布尔值是最基础的数据类型，在 TypeScript 中，使用 boolean 定义布尔值类型  ES6数据类型">
<meta property="og:locale" content="zh-Hans">
<meta property="og:image" content="https://poetries1.gitee.io/img-repo/20190903/base-1.webp">
<meta property="og:image" content="https://poetries1.gitee.io/img-repo/20190903/base-2.webp">
<meta property="og:image" content="https://poetries1.gitee.io/img-repo/20190903/base-3.webp">
<meta property="og:image" content="https://poetries1.gitee.io/img-repo/20190903/base-4.webp">
<meta property="og:image" content="https://poetries1.gitee.io/img-repo/20190903/base-5.webp">
<meta property="og:image" content="https://poetries1.gitee.io/img-repo/20190903/base-6.webp">
<meta property="og:image" content="https://poetries1.gitee.io/img-repo/20190903/base-7.webp">
<meta property="og:image" content="https://poetries1.gitee.io/img-repo/20190903/base-8.webp">
<meta property="og:image" content="https://poetries1.gitee.io/img-repo/20190903/base-9.webp">
<meta property="og:image" content="https://poetries1.gitee.io/img-repo/20190903/base-10.webp">
<meta property="og:image" content="https://pic2.zhimg.com/80/v2-fdfb8e5f2be67d8c978e216254b80a9d_hd.jpg">
<meta property="og:image" content="https://poetries1.gitee.io/img-repo/20190903/3.png">
<meta property="og:image" content="https://poetries1.gitee.io/img-repo/20190903/4.png">
<meta property="og:image" content="https://poetries1.gitee.io/img-repo/20190903/5.png">
<meta property="og:image" content="https://poetries1.gitee.io/img-repo/20190903/6.png">
<meta property="og:image" content="https://poetries1.gitee.io/img-repo/20190903/7.png">
<meta property="og:image" content="https://poetries1.gitee.io/img-repo/20190903/8.png">
<meta property="og:image" content="https://poetries1.gitee.io/img-repo/20190903/9.png">
<meta property="og:image" content="https://poetries1.gitee.io/img-repo/20190903/10.png">
<meta property="og:image" content="https://poetries1.gitee.io/img-repo/20190903/gongcheng-1.webp">
<meta property="og:image" content="https://poetries1.gitee.io/img-repo/20190903/gongcheng-2.webp">
<meta property="og:image" content="https://poetries1.gitee.io/img-repo/20190903/gongcheng-3.webp">
<meta property="og:image" content="https://poetries1.gitee.io/img-repo/20190903/gongcheng-4.webp">
<meta property="og:image" content="https://poetries1.gitee.io/img-repo/20190903/gongcheng-5.webp">
<meta property="og:image" content="https://poetries1.gitee.io/img-repo/20190903/gongcheng-6.webp">
<meta property="og:image" content="https://poetries1.gitee.io/img-repo/20190903/gongcheng-7.webp">
<meta property="og:image" content="https://poetries1.gitee.io/img-repo/20190903/gongcheng-8.webp">
<meta property="og:image" content="https://poetries1.gitee.io/img-repo/20190903/1.png">
<meta property="og:image" content="https://poetries1.gitee.io/img-repo/20190903/2.png">
<meta property="og:updated_time" content="2020-08-15T04:25:31.938Z">
<meta name="twitter:card" content="summary">
<meta name="twitter:title" content="Typescript实践总结[基础+工程+实践]">
<meta name="twitter:description" content="第一章 基础篇 TS基础篇   一、基本类型 JavaScript 的类型分为两种：原始数据类型和对象类型。 原始数据类型包括：布尔值、数值、字符串、null、undefined 以及 ES6 中的新类型 Symbol 本节主要介绍前五种原始数据类型在 TypeScript 中的应用。 布尔值是最基础的数据类型，在 TypeScript 中，使用 boolean 定义布尔值类型  ES6数据类型">
<meta name="twitter:image" content="https://poetries1.gitee.io/img-repo/20190903/base-1.webp">

  

  
    <link rel="icon" href="/favicon.ico">
  

  <link href="/css/styles.css?v=c114cbeddx" rel="stylesheet">
<link href="/css/other.css?v=c114cbeddx" rel="stylesheet">


  
    <link rel="stylesheet" href="/css/personal-style.css">
  

  

  
  <script type="text/javascript">
    var _hmt = _hmt || [];
    (function() {
      var hm = document.createElement("script");
      hm.src = "//hm.baidu.com/hm.js?40b1f89aa80f2527b3db779c6898c879";
      var s = document.getElementsByTagName("script")[0];
      s.parentNode.insertBefore(hm, s);
    })();
  </script>


  
  <script type="text/javascript">
	(function(){
	    var bp = document.createElement('script');
	    var curProtocol = window.location.protocol.split(':')[0];
	    if (curProtocol === 'https') {
	        bp.src = 'https://zz.bdstatic.com/linksubmit/push.js';        
	    }
	    else {
	        bp.src = 'http://push.zhanzhang.baidu.com/push.js';
	    }
	    var s = document.getElementsByTagName("script")[0];
	    s.parentNode.insertBefore(bp, s);
	})();
  </script>



  
    <script async src="https://busuanzi.ibruce.info/busuanzi/2.3/busuanzi.pure.mini.js"></script>
    <link rel="stylesheet" href="//cdn.bootcss.com/font-awesome/4.3.0/css/font-awesome.min.css">
  

  <!-- 聊天系统 -->
  
    
   <link type="text/css" rel="stylesheet" href="/renxi/default.css">
   <style>
      #modal {
        position: static !important;
      }
      .filter {
        width: 100%;
        height: 100%;
        position: absolute;
        top: 0;
        left: 0;
        background: #fe5757;
        animation: colorChange 30s ease-in-out infinite;
        animation-fill-mode: both;
        mix-blend-mode: overlay;
      }
  
      @keyframes colorChange {
        0%, 100% {
            opacity: 0;
        }
        50% {
            opacity: .9;
        }
      }
   </style>
</head>
</html>
<body>
  
  
    <span id="toolbox-mobile" class="toolbox-mobile">导航</span>
  

  <div class="post-header CENTER">
   
  <div class="toolbox">
    <a class="toolbox-entry" href="/">
      <span class="toolbox-entry-text">导航</span>
      <i class="icon-angle-down"></i>
      <i class="icon-home"></i>
    </a>
    <ul class="list-toolbox">
      
        <li class="item-toolbox">
          <a
            class="CIRCLE"
            href="/archives/"
            rel="noopener noreferrer"
            target="_self"
            >
            博客
          </a>
        </li>
      
        <li class="item-toolbox">
          <a
            class="CIRCLE"
            href="/categories/"
            rel="noopener noreferrer"
            target="_self"
            >
            分类
          </a>
        </li>
      
        <li class="item-toolbox">
          <a
            class="CIRCLE"
            href="/tags/"
            rel="noopener noreferrer"
            target="_self"
            >
            标签
          </a>
        </li>
      
        <li class="item-toolbox">
          <a
            class="CIRCLE"
            href="/search/"
            rel="noopener noreferrer"
            target="_self"
            >
            搜索
          </a>
        </li>
      
        <li class="item-toolbox">
          <a
            class="CIRCLE"
            href="/link/"
            rel="noopener noreferrer"
            target="_self"
            >
            友链
          </a>
        </li>
      
        <li class="item-toolbox">
          <a
            class="CIRCLE"
            href="/about/"
            rel="noopener noreferrer"
            target="_self"
            >
            关于
          </a>
        </li>
      
    </ul>
  </div>


</div>


  <div id="toc" class="toc-article">
    <strong class="toc-title">文章目录<i class="iconfont toc-title" style="display:inline-block;color:#87998d;width:20px;height:20px;">&#xf004b;</i></strong>
    <ol class="toc"><li class="toc-item toc-level-1"><a class="toc-link" href="#第一章-基础篇"><span class="toc-text">第一章 基础篇</span></a><ol class="toc-child"><li class="toc-item toc-level-2"><a class="toc-link" href="#一、基本类型"><span class="toc-text">一、基本类型</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#二、任意值"><span class="toc-text">二、任意值</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#三、类型推论"><span class="toc-text">三、类型推论</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#四、联合类型"><span class="toc-text">四、联合类型</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#五、对象的类型——接口"><span class="toc-text">五、对象的类型——接口</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#六、数组的类型"><span class="toc-text">六、数组的类型</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#七、函数的类型"><span class="toc-text">七、函数的类型</span></a><ol class="toc-child"><li class="toc-item toc-level-3"><a class="toc-link" href="#7-1-函数相关知识点梳理"><span class="toc-text">7.1 函数相关知识点梳理</span></a></li></ol></li><li class="toc-item toc-level-2"><a class="toc-link" href="#八、类型断言"><span class="toc-text">八、类型断言</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#九、类型别名"><span class="toc-text">九、类型别名</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#十、枚举"><span class="toc-text">十、枚举</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#十一、类"><span class="toc-text">十一、类</span></a><ol class="toc-child"><li class="toc-item toc-level-3"><a class="toc-link" href="#11-1类与接口的关系"><span class="toc-text">11.1类与接口的关系</span></a></li></ol></li><li class="toc-item toc-level-2"><a class="toc-link" href="#十二、public-private-和-protected"><span class="toc-text">十二、public private 和 protected</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#十三、泛型"><span class="toc-text">十三、泛型</span></a><ol class="toc-child"><li class="toc-item toc-level-3"><a class="toc-link" href="#13-1-泛型函数和接口"><span class="toc-text">13.1 泛型函数和接口</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#13-2-泛型类与泛型约束"><span class="toc-text">13.2 泛型类与泛型约束</span></a></li></ol></li><li class="toc-item toc-level-2"><a class="toc-link" href="#十四、类型检查机制"><span class="toc-text">十四、类型检查机制</span></a><ol class="toc-child"><li class="toc-item toc-level-3"><a class="toc-link" href="#14-1-类型检查机制"><span class="toc-text">14.1 类型检查机制</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#14-2-类型保护机制"><span class="toc-text">14.2 类型保护机制</span></a><ol class="toc-child"><li class="toc-item toc-level-4"><a class="toc-link" href="#14-2-1-用户自定义的类型保护"><span class="toc-text">14.2.1 用户自定义的类型保护</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#14-2-2-typeof-类型保护"><span class="toc-text">14.2.2 typeof 类型保护</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#14-2-3-instanceof-类型保护"><span class="toc-text">14.2.3 instanceof 类型保护</span></a></li></ol></li></ol></li><li class="toc-item toc-level-2"><a class="toc-link" href="#十五、高级类型"><span class="toc-text">十五、高级类型</span></a><ol class="toc-child"><li class="toc-item toc-level-3"><a class="toc-link" href="#15-1-交叉类型（取并集）"><span class="toc-text">15.1 交叉类型（取并集）</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#15-2-索引类型"><span class="toc-text">15.2 索引类型</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#15-3-映射类型"><span class="toc-text">15.3 映射类型</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#15-4-条件类型"><span class="toc-text">15.4 条件类型</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#15-5-联合类型"><span class="toc-text">15.5 联合类型</span></a></li></ol></li><li class="toc-item toc-level-2"><a class="toc-link" href="#十六、初学者的困惑"><span class="toc-text">十六、初学者的困惑</span></a><ol class="toc-child"><li class="toc-item toc-level-3"><a class="toc-link" href="#16-1-如何优雅的声明类型"><span class="toc-text">16.1 如何优雅的声明类型</span></a><ol class="toc-child"><li class="toc-item toc-level-4"><a class="toc-link" href="#16-1-1-基础"><span class="toc-text">16.1.1 基础</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#16-1-2-糅合"><span class="toc-text">16.1.2 糅合</span></a></li></ol></li><li class="toc-item toc-level-3"><a class="toc-link" href="#16-2-如何引用外部库"><span class="toc-text">16.2 如何引用外部库</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#16-3-如何组织一个-TS-项目"><span class="toc-text">16.3 如何组织一个 TS 项目</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#16-4-TSX-和-JSX"><span class="toc-text">16.4 TSX 和 JSX</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#16-5-变量的-Type-怎么找"><span class="toc-text">16.5 变量的 Type 怎么找</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#16-6-常见-Types-之-DOM"><span class="toc-text">16.6 常见 Types 之 DOM</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#16-7-常见-Types-之-React"><span class="toc-text">16.7 常见 Types 之 React</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#16-8-多重-extends"><span class="toc-text">16.8 多重 extends</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#16-9-obj-prop-无法访问怎么办"><span class="toc-text">16.9 obj[prop] 无法访问怎么办</span></a></li></ol></li><li class="toc-item toc-level-2"><a class="toc-link" href="#十七、其他技巧"><span class="toc-text">十七、其他技巧</span></a></li></ol></li><li class="toc-item toc-level-1"><a class="toc-link" href="#第二章-工程篇"><span class="toc-text">第二章 工程篇</span></a><ol class="toc-child"><li class="toc-item toc-level-2"><a class="toc-link" href="#一、使用命名空间"><span class="toc-text">一、使用命名空间</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#二、理解联合声明"><span class="toc-text">二、理解联合声明</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#三、如何编写声明文件–引入类库"><span class="toc-text">三、如何编写声明文件–引入类库</span></a><ol class="toc-child"><li class="toc-item toc-level-3"><a class="toc-link" href="#3-1-三种类库声明文件写法"><span class="toc-text">3.1 三种类库声明文件写法</span></a><ol class="toc-child"><li class="toc-item toc-level-4"><a class="toc-link" href="#3-1-1-全局库"><span class="toc-text">3.1.1 全局库</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#3-1-2-模块类库"><span class="toc-text">3.1.2 模块类库</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#3-1-3-UMD类库"><span class="toc-text">3.1.3 UMD类库</span></a></li></ol></li><li class="toc-item toc-level-3"><a class="toc-link" href="#3-2-两种插件声明文件写法"><span class="toc-text">3.2 两种插件声明文件写法</span></a><ol class="toc-child"><li class="toc-item toc-level-4"><a class="toc-link" href="#3-2-1-模块化插件declare-module"><span class="toc-text">3.2.1 模块化插件declare module</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#3-2-2-全局插件declare-global"><span class="toc-text">3.2.2 全局插件declare global</span></a></li></ol></li><li class="toc-item toc-level-3"><a class="toc-link" href="#3-3-jquery声明文件示例"><span class="toc-text">3.3 jquery声明文件示例</span></a></li></ol></li><li class="toc-item toc-level-2"><a class="toc-link" href="#四、配置tsconfig-json"><span class="toc-text">四、配置tsconfig.json</span></a><ol class="toc-child"><li class="toc-item toc-level-3"><a class="toc-link" href="#4-1-基础配置"><span class="toc-text">4.1 基础配置</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#4-2-工程引用配置多个项目"><span class="toc-text">4.2 工程引用配置多个项目</span></a></li></ol></li><li class="toc-item toc-level-2"><a class="toc-link" href="#五、编译工具ts-loader、ts-lint"><span class="toc-text">五、编译工具ts-loader、ts-lint</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#六、使用jest进行单元测试"><span class="toc-text">六、使用jest进行单元测试</span></a></li></ol></li><li class="toc-item toc-level-1"><a class="toc-link" href="#第三章-项目实战"><span class="toc-text">第三章 项目实战</span></a><ol class="toc-child"><li class="toc-item toc-level-2"><a class="toc-link" href="#一、思维导图"><span class="toc-text">一、思维导图</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#二、React项目实践"><span class="toc-text">二、React项目实践</span></a><ol class="toc-child"><li class="toc-item toc-level-3"><a class="toc-link" href="#2-1-手动创建react项目"><span class="toc-text">2.1 手动创建react项目</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#2-2-使用脚手架安装"><span class="toc-text">2.2 使用脚手架安装</span></a><ol class="toc-child"><li class="toc-item toc-level-4"><a class="toc-link" href="#2-2-1-函数组件"><span class="toc-text">2.2.1 函数组件</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#2-2-2-类组件"><span class="toc-text">2.2.2 类组件</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#2-2-3-高阶组件"><span class="toc-text">2.2.3 高阶组件</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#2-2-4-Hooks组件"><span class="toc-text">2.2.4 Hooks组件</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#2-2-5-事件处理与数据请求"><span class="toc-text">2.2.5 事件处理与数据请求</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#2-2-6-列表渲染"><span class="toc-text">2.2.6 列表渲染</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#2-2-7-Redux与类型"><span class="toc-text">2.2.7 Redux与类型</span></a></li></ol></li><li class="toc-item toc-level-3"><a class="toc-link" href="#2-3-服务端使用Typescript"><span class="toc-text">2.3 服务端使用Typescript</span></a></li></ol></li><li class="toc-item toc-level-2"><a class="toc-link" href="#三、Vue项目实践"><span class="toc-text">三、Vue项目实践</span></a></li></ol></li><li class="toc-item toc-level-1"><a class="toc-link" href="#更多资料"><span class="toc-text">更多资料</span></a></li></ol>
  </div>
  




<div class="content content-post CENTER">
   <!-- canvas 彩带 -->
<canvas id="evanyou" width="1302" height="678" style="position: fixed;width: 100%;height: 100%;top: 0;left:0;z-index:-1;"></canvas>

<article id="post-ts-in-action" class="article article-type-post" itemprop="blogPost">
  <header class="article-header" style="position:relative;">
    <h1 class="post-title">Typescript实践总结[基础+工程+实践]</h1>

    <div class="article-meta">
      <span>
        <i class="icon-calendar"></i>
        <span>2019.09.03</span>
      </span>

      
        <span class="article-author">
          <i class="icon-user"></i>
          <span>Poetry</span>
        </span>
      

      
  <span class="article-category">
    <i class="icon-list"></i>
    <a class="article-category-link" href="/categories/Front-End/">Front-End</a>
  </span>



      

      
      <i class="fa fa-eye"></i> 
        <span id="busuanzi_container_page_pv">
           &nbsp热度 <span id="busuanzi_value_page_pv">
           <i class="fa fa-spinner fa-spin"></i></span>℃
        </span>
      
      
       
          <span class="post-count">
            <i class="fa fa-file-word-o"></i>&nbsp
            <span>字数统计 13.7k字</span>
          </span>

          <span class="post-count">
            <i class="fa fa-columns"></i>&nbsp
            <span>阅读时长 61分</span>
          </span>
      
      
    </div>

    <i class="iconfont" id="toc-eye" style="display:inline-block;color:#b36619;position:absolute;top:0;right:0;cursor:pointer;
    font-size: 24px;">&#xe61c;</i>

  </header>

  <div class="article-content">
    
      <div id="container">
        <h1 id="第一章-基础篇"><a href="#第一章-基础篇" class="headerlink" title="第一章 基础篇"></a>第一章 基础篇</h1><blockquote>
<p>TS基础篇</p>
</blockquote>
<p><img src="https://poetries1.gitee.io/img-repo/20190903/base-1.webp" alt><br><img src="https://poetries1.gitee.io/img-repo/20190903/base-2.webp" alt><br><img src="https://poetries1.gitee.io/img-repo/20190903/base-3.webp" alt><br><img src="https://poetries1.gitee.io/img-repo/20190903/base-4.webp" alt><br><img src="https://poetries1.gitee.io/img-repo/20190903/base-5.webp" alt><br><img src="https://poetries1.gitee.io/img-repo/20190903/base-6.webp" alt><br><img src="https://poetries1.gitee.io/img-repo/20190903/base-7.webp" alt><br><img src="https://poetries1.gitee.io/img-repo/20190903/base-8.webp" alt><br><img src="https://poetries1.gitee.io/img-repo/20190903/base-9.webp" alt><br><img src="https://poetries1.gitee.io/img-repo/20190903/base-10.webp" alt></p>
<h2 id="一、基本类型"><a href="#一、基本类型" class="headerlink" title="一、基本类型"></a>一、基本类型</h2><ul>
<li><code>JavaScript</code> 的类型分为两种：原始数据类型和对象类型。</li>
<li>原始数据类型包括：布尔值、数值、字符串、<code>null</code>、<code>undefined</code> 以及 ES6 中的新类型 <code>Symbol</code></li>
<li>本节主要介绍前五种原始数据类型在 <code>TypeScript</code> 中的应用。</li>
<li>布尔值是最基础的数据类型，在 <code>TypeScript</code> 中，使用 <code>boolean</code> 定义布尔值类型</li>
</ul>
<p><strong>ES6数据类型</strong></p>
<ul>
<li><code>Boolean</code></li>
<li><code>Number</code></li>
<li><code>String</code></li>
<li><code>Array</code></li>
<li><code>Function</code></li>
<li><code>Object</code></li>
<li><code>Symbol</code></li>
<li><code>undefined</code></li>
<li><code>null</code></li>
</ul>
<p><strong>Typescript数据类型</strong></p>
<ul>
<li><code>Boolean</code></li>
<li><code>Number</code></li>
<li><code>String</code></li>
<li><code>Array</code></li>
<li><code>Function</code></li>
<li><code>Object</code></li>
<li><code>Symbol</code></li>
<li><code>undefined</code></li>
<li><code>null</code></li>
<li><code>void</code></li>
<li><code>any</code></li>
<li><code>never</code></li>
<li>元组</li>
<li>枚举</li>
<li>高级类型</li>
</ul>
<p><strong>正确的写法</strong></p>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line">➖➖➖➖➖➖➖➖➖布尔➖➖➖➖➖➖➖➖➖</span><br><span class="line"><span class="comment">// 布尔值</span></span><br><span class="line"><span class="keyword">let</span> isDone: boolean = <span class="literal">false</span>;  </span><br><span class="line"></span><br><span class="line"><span class="comment">// 事实上 `new Boolean()` 返回的是一个 `Boolean` 对象</span></span><br><span class="line"><span class="keyword">let</span> createdByNewBoolean: <span class="built_in">Boolean</span> = <span class="keyword">new</span> <span class="built_in">Boolean</span>(<span class="number">1</span>);</span><br><span class="line"></span><br><span class="line"><span class="comment">//(直接调用 `Boolean` 也可以返回一个 `boolean` 类型) </span></span><br><span class="line"><span class="keyword">let</span> createdByBoolean: boolean = <span class="built_in">Boolean</span>(<span class="number">1</span>); </span><br><span class="line"></span><br><span class="line">➖➖➖➖➖➖➖➖➖数值➖➖➖➖➖➖➖➖➖</span><br><span class="line"><span class="comment">// 数值</span></span><br><span class="line"><span class="keyword">let</span> decLiteral: number = <span class="number">6</span>;</span><br><span class="line"><span class="keyword">let</span> hexLiteral: number = <span class="number">0xf00d</span>;</span><br><span class="line"></span><br><span class="line"><span class="comment">// ES6 中的二进制表示法</span></span><br><span class="line"><span class="keyword">let</span> binaryLiteral: number = <span class="number">0b1010</span>;</span><br><span class="line"></span><br><span class="line"><span class="comment">// ES6 中的八进制表示法</span></span><br><span class="line"><span class="keyword">let</span> octalLiteral: number = <span class="number">0o744</span>;</span><br><span class="line"><span class="keyword">let</span> notANumber: number = <span class="literal">NaN</span>;</span><br><span class="line"><span class="keyword">let</span> infinityNumber: number = <span class="literal">Infinity</span>;</span><br><span class="line">➖➖➖➖➖➖➖➖➖字符串➖➖➖➖➖➖➖➖➖</span><br><span class="line"><span class="keyword">let</span> myName: string = <span class="string">'Tom'</span>;</span><br><span class="line">➖➖➖➖➖➖➖➖➖空值➖➖➖➖➖➖➖➖➖</span><br><span class="line"><span class="comment">// 没有返回值的函数为void</span></span><br><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">alertName</span>(<span class="params"></span>): <span class="title">void</span> </span>&#123;</span><br><span class="line">    alert(<span class="string">'My name is Tom'</span>);</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">//声明一个 void 类型的只能将它赋值为 undefined 和 null</span></span><br><span class="line"><span class="keyword">let</span> unusable: <span class="keyword">void</span> = <span class="literal">undefined</span>;</span><br><span class="line">➖➖➖➖➖➖➖➖➖Null 和 Undefined➖➖➖➖➖➖➖➖➖</span><br><span class="line"><span class="comment">// undefined 类型的变量只能被赋值为 undefined，null 类型的变量只能被赋值为 null</span></span><br><span class="line"><span class="keyword">let</span> u: <span class="literal">undefined</span> = <span class="literal">undefined</span>;</span><br><span class="line"><span class="keyword">let</span> n: <span class="literal">null</span> = <span class="literal">null</span>;</span><br></pre></td></tr></table></figure>
<p><strong>错误的写法</strong></p>
<blockquote>
<p>注意:正确的很好记,大多数人都会写正确的,关键是要记住这些错误的!!!</p>
</blockquote>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line">➖➖➖➖➖➖➖➖➖布尔➖➖➖➖➖➖➖➖➖</span><br><span class="line"><span class="comment">// 注意，使用构造函数 `Boolean` 创造的对象不是布尔值</span></span><br><span class="line"><span class="keyword">let</span> createdByNewBoolean: boolean = <span class="keyword">new</span> <span class="built_in">Boolean</span>(<span class="number">1</span>);❌</span><br><span class="line"></span><br><span class="line">➖➖➖➖➖➖➖➖➖数值➖➖➖➖➖➖➖➖➖</span><br><span class="line"><span class="keyword">let</span> decLiteral: number = <span class="string">"6"</span>;❌</span><br><span class="line"></span><br><span class="line">➖➖➖➖➖➖➖➖➖字符串➖➖➖➖➖➖➖➖➖</span><br><span class="line"><span class="keyword">let</span> myName: string = <span class="number">999</span>;❌</span><br><span class="line"></span><br><span class="line">➖➖➖➖➖➖➖➖➖空值➖➖➖➖➖➖➖➖➖</span><br><span class="line"><span class="comment">// 没有返回值的函数为void</span></span><br><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">alertName</span>(<span class="params"></span>): <span class="title">void</span> </span>&#123;❌</span><br><span class="line">   <span class="keyword">return</span> <span class="number">666</span>;</span><br><span class="line">&#125;</span><br><span class="line"><span class="comment">//声明一个 void 类型的只能将它赋值为 undefined 和 null</span></span><br><span class="line"><span class="keyword">let</span> unusable: <span class="keyword">void</span> = <span class="string">'I love you'</span>;❌</span><br><span class="line"></span><br><span class="line">➖➖➖➖➖➖➖➖➖Null 和 Undefined➖➖➖➖➖➖➖➖➖</span><br><span class="line"><span class="comment">// undefined 类型的变量只能被赋值为 undefined，null 类型的变量只能被赋值为 null</span></span><br><span class="line"><span class="keyword">let</span> u: <span class="literal">undefined</span> = <span class="number">888</span>;❌</span><br><span class="line"><span class="keyword">let</span> n: <span class="literal">null</span> = <span class="number">999</span>;❌</span><br></pre></td></tr></table></figure>
<h2 id="二、任意值"><a href="#二、任意值" class="headerlink" title="二、任意值"></a>二、任意值</h2><p><strong>正确的写法</strong></p>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line"><span class="comment">// 顾名思义,可以被任何值赋值</span></span><br><span class="line"><span class="keyword">let</span> anyThing: any = <span class="string">'hello'</span>;</span><br><span class="line"><span class="keyword">let</span> anyThing: any = <span class="number">888</span>;</span><br><span class="line"><span class="keyword">let</span> anyThing: any = <span class="literal">true</span>;</span><br><span class="line"><span class="keyword">let</span> anyThing: any = <span class="literal">null</span>;</span><br><span class="line"><span class="keyword">let</span> anyThing: any = <span class="literal">undefined</span>;</span><br><span class="line"></span><br><span class="line"><span class="comment">// 变量如果在声明的时候，未指定其类型，那么它会被识别为任意值类型：</span></span><br><span class="line"><span class="keyword">let</span> any;</span><br><span class="line">any =<span class="literal">true</span>;</span><br></pre></td></tr></table></figure>
<h2 id="三、类型推论"><a href="#三、类型推论" class="headerlink" title="三、类型推论"></a>三、类型推论</h2><p><strong>正确的写法</strong></p>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line"><span class="comment">// 如果没有明确的指定类型，那么 TypeScript 会依照类型推论（Type Inference）的规则推断出一个类型。</span></span><br><span class="line"><span class="keyword">let</span> myFavoriteNumber = <span class="string">'seven'</span>;  </span><br><span class="line"><span class="comment">//等价于</span></span><br><span class="line"><span class="keyword">let</span> myFavoriteNumber :string= <span class="string">'seven'</span>;</span><br></pre></td></tr></table></figure>
<p><strong>错误的写法</strong></p>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line"><span class="comment">// 第一句已经被推论为String类型了</span></span><br><span class="line"><span class="keyword">let</span> myFavoriteNumber = <span class="string">'seven'</span>;</span><br><span class="line">myFavoriteNumber = <span class="number">7</span>;❌</span><br></pre></td></tr></table></figure>
<h2 id="四、联合类型"><a href="#四、联合类型" class="headerlink" title="四、联合类型"></a>四、联合类型</h2><p><strong>正确的写法</strong></p>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line"><span class="comment">// 联合类型（Union Types）表示取值可以为多种类型中的一种。</span></span><br><span class="line"><span class="comment">// 当你允许某个变量被赋值多种类型的时候,使用联合类型,管道符进行连接</span></span><br><span class="line"><span class="keyword">let</span> myFavoriteNumber: string | number;</span><br><span class="line">myFavoriteNumber = <span class="string">'seven'</span>;</span><br><span class="line">myFavoriteNumber = <span class="number">7</span>;</span><br><span class="line"></span><br><span class="line"><span class="comment">// 也可用于方法的参数定义, 都有toString方法,访问 string 和 number 的共有属性是没问题的</span></span><br><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">getString</span>(<span class="params">something: string | number</span>): <span class="title">string</span> </span>&#123;</span><br><span class="line">    <span class="keyword">return</span> something.toString();</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<p><strong>错误的写法</strong></p>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line"><span class="comment">// number类型没有length属性.所以编译错误,因为我们只能访问此联合类型的所有类型里共有的属性或方法：</span></span><br><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">getLength</span>(<span class="params">something: string | number</span>): <span class="title">number</span> </span>&#123;❌</span><br><span class="line">    <span class="keyword">return</span> something.length;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<h2 id="五、对象的类型——接口"><a href="#五、对象的类型——接口" class="headerlink" title="五、对象的类型——接口"></a>五、对象的类型——接口</h2><p><strong>正确的写法</strong></p>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line"><span class="comment">// 赋值的时候，变量的形状必须和接口的形状保持一致(不能多也不能少,类型还必须一致)</span></span><br><span class="line">interface Person &#123;</span><br><span class="line">    name: string;</span><br><span class="line">    age: number;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">let</span> tom: Person = &#123;</span><br><span class="line">    name: <span class="string">'Tom'</span>,</span><br><span class="line">    age: <span class="number">25</span></span><br><span class="line">&#125;;</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">IUserInfo&#123;</span><br><span class="line">  age : any;<span class="comment">//定义一个任何变量的 age.</span></span><br><span class="line">  userName :string;<span class="comment">//定义一个 username.</span></span><br><span class="line">&#125;</span><br><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">getUserInfo</span>(<span class="params">user : IUserInfo</span>):<span class="title">string</span></span>&#123;</span><br><span class="line">    <span class="keyword">return</span> user.age+<span class="string">"======"</span>+user.userName; 	</span><br><span class="line">&#125;</span><br><span class="line">  ➖➖➖➖➖➖➖➖➖可选属性➖➖➖➖➖➖➖➖➖</span><br><span class="line"></span><br><span class="line">interface Person &#123;</span><br><span class="line">    name: string;</span><br><span class="line">    age?: number; <span class="comment">// 表示这个属性可有可无</span></span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">let</span> tom: Person = &#123;</span><br><span class="line">    name: <span class="string">'Tom'</span></span><br><span class="line">&#125;;</span><br><span class="line"><span class="comment">// 可索引签名</span></span><br><span class="line">interface StringArrary &#123;</span><br><span class="line">  [index]: string <span class="comment">// 数字索引。通过数字索引，返回string类型</span></span><br><span class="line">  [string]: string <span class="comment">// 字符串索引签名。两者不能混用，一起使用的前提是数字索引是字符串索引的子集</span></span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">let</span> myArr: StringArrary</span><br><span class="line">myArr = [<span class="string">'test1'</span>,<span class="string">'test2'</span>]</span><br><span class="line"><span class="keyword">let</span> myString = myArr[<span class="number">0</span>]</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">  ➖➖➖➖➖➖➖➖➖任意属性➖➖➖➖➖➖➖➖➖</span><br><span class="line"></span><br><span class="line"><span class="comment">//希望一个接口允许有任意的属性，可以使用如下方式：旦定义了任意属性，那么确定属性和可选属性的类型都必须是它的类型的子集</span></span><br><span class="line">interface Person &#123;</span><br><span class="line">    name: string;</span><br><span class="line">    age?: number;</span><br><span class="line">    [propName: string]: any;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">let</span> tom: Person = &#123;</span><br><span class="line">    name: <span class="string">'Tom'</span>,</span><br><span class="line">    gender: <span class="string">'male'</span> <span class="comment">// 可以加其他的属性</span></span><br><span class="line">&#125;;</span><br><span class="line"></span><br><span class="line">➖➖➖➖➖➖➖➖➖只读属性➖➖➖➖➖➖➖➖➖</span><br><span class="line">interface Person &#123;</span><br><span class="line">    readonly id: number; <span class="comment">// </span></span><br><span class="line">    name: string;</span><br><span class="line">    age?: number;</span><br><span class="line">    [propName: string]: any;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">let</span> tom: Person = &#123;</span><br><span class="line">    id: <span class="number">89757</span>, <span class="comment">// 只读</span></span><br><span class="line">    name: <span class="string">'Tom'</span>,</span><br><span class="line">    gender: <span class="string">'male'</span></span><br><span class="line">&#125;;</span><br></pre></td></tr></table></figure>
<p><strong>错误的写法</strong></p>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line"><span class="comment">// 一旦定义了任意属性，那么确定属性和可选属性的类型都必须是它的类型的子集</span></span><br><span class="line">interface Person &#123;</span><br><span class="line">    name: string;</span><br><span class="line">    age?: number;</span><br><span class="line">    [propName: string]: string;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">let</span> tom: Person = &#123;</span><br><span class="line">    name: <span class="string">'Tom'</span>,</span><br><span class="line">    age: <span class="number">25</span>,</span><br><span class="line">    gender: <span class="string">'male'</span>❌</span><br><span class="line">&#125;;</span><br><span class="line">上例中，任意属性的值允许是 string，但是可选属性 age 的值却是 number，number 不是 string 的子属性，所以报错了。</span><br><span class="line"></span><br><span class="line">➖➖➖➖➖➖➖➖➖只读属性➖➖➖➖➖➖➖➖➖</span><br><span class="line">interface Person &#123;</span><br><span class="line">    readonly id: number;</span><br><span class="line">    name: string;</span><br><span class="line">    age?: number;</span><br><span class="line">    [propName: string]: any;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">let</span> tom: Person = &#123;</span><br><span class="line">    name: <span class="string">'Tom'</span>,</span><br><span class="line">    gender: <span class="string">'male'</span></span><br><span class="line">&#125;;</span><br><span class="line"></span><br><span class="line">tom.id = <span class="number">89757</span>; <span class="comment">// 不能被二次赋值❌</span></span><br></pre></td></tr></table></figure>
<p><strong>数组只读属性</strong></p>
<figure class="highlight plain"><table><tr><td class="code"><pre><span class="line">let myARr:readonlyArrary&lt;number&gt; = [1,2,3]</span><br></pre></td></tr></table></figure>
<h2 id="六、数组的类型"><a href="#六、数组的类型" class="headerlink" title="六、数组的类型"></a>六、数组的类型</h2><p><strong>正确的做法</strong></p>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line"><span class="keyword">let</span> fibonacci: number[] = [<span class="number">1</span>, <span class="number">1</span>, <span class="number">2</span>, <span class="number">3</span>, <span class="number">5</span>];</span><br><span class="line"><span class="keyword">let</span> fibonacci: <span class="built_in">Array</span>&lt;number&gt; = [<span class="number">1</span>, <span class="number">1</span>, <span class="number">2</span>, <span class="number">3</span>, <span class="number">5</span>];</span><br><span class="line"></span><br><span class="line">➖➖➖➖➖➖➖➖➖用接口表示数组➖➖➖➖➖➖➖➖➖</span><br><span class="line">interface NumberArray &#123;</span><br><span class="line">    [index: number]: number;</span><br><span class="line">&#125;</span><br><span class="line"><span class="keyword">let</span> fibonacci: NumberArray = [<span class="number">1</span>, <span class="number">1</span>, <span class="number">2</span>, <span class="number">3</span>, <span class="number">5</span>];</span><br><span class="line"></span><br><span class="line">➖➖➖➖➖➖➖➖➖any 在数组中的应用➖➖➖➖➖➖➖➖➖</span><br><span class="line"><span class="keyword">let</span> list: any[] = [<span class="string">'Xcat Liu'</span>, <span class="number">25</span>, &#123; <span class="attr">website</span>: <span class="string">'http://xcatliu.com'</span> &#125;];</span><br><span class="line"></span><br><span class="line">➖➖➖➖➖➖➖➖➖类数组➖➖➖➖➖➖➖➖➖</span><br><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">sum</span>(<span class="params"></span>) </span>&#123;</span><br><span class="line">    <span class="keyword">let</span> args: IArguments = <span class="built_in">arguments</span>;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<p><strong>错误的做法</strong></p>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line"><span class="comment">// 数组的项中不允许出现其他的类型：</span></span><br><span class="line"><span class="keyword">let</span> fibonacci: number[] = [<span class="number">1</span>, <span class="string">'1'</span>, <span class="number">2</span>, <span class="number">3</span>, <span class="number">5</span>];❌</span><br><span class="line"></span><br><span class="line"><span class="comment">// push 方法只允许传入 number 类型的参数，但是却传了一个 string 类型的参数，所以报错了。</span></span><br><span class="line"><span class="keyword">let</span> fibonacci: number[] = [<span class="number">1</span>, <span class="number">1</span>, <span class="number">2</span>, <span class="number">3</span>, <span class="number">5</span>];</span><br><span class="line">fibonacci.push(<span class="string">'8'</span>);❌</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="comment">// 类数组（Array-like Object）不是数组类型，比如 arguments</span></span><br><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">sum</span>(<span class="params"></span>) </span>&#123;❌</span><br><span class="line">    <span class="keyword">let</span> args: number[] = <span class="built_in">arguments</span>;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<h2 id="七、函数的类型"><a href="#七、函数的类型" class="headerlink" title="七、函数的类型"></a>七、函数的类型</h2><p><strong>正确的做法</strong></p>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line"><span class="comment">// 需要把输入和输出都考虑到</span></span><br><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">sum</span>(<span class="params">x: number, y: number</span>): <span class="title">number</span> </span>&#123;</span><br><span class="line">    <span class="keyword">return</span> x + y;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">➖➖➖➖➖➖➖➖➖函数表达式➖➖➖➖➖➖➖➖➖</span><br><span class="line"><span class="keyword">let</span> mySum = <span class="function"><span class="keyword">function</span> (<span class="params">x: number, y: number</span>): <span class="title">number</span> </span>&#123;</span><br><span class="line">    <span class="keyword">return</span> x + y;</span><br><span class="line">&#125;;</span><br><span class="line"><span class="comment">// 不要混淆了 TypeScript 中的 =&gt; 和 ES6 中的 =&gt;</span></span><br><span class="line"><span class="keyword">let</span> mySum: <span class="function">(<span class="params">x: number, y: number</span>) =&gt;</span> number = <span class="function"><span class="keyword">function</span> (<span class="params">x: number, y: number</span>): <span class="title">number</span> </span>&#123;</span><br><span class="line">    <span class="keyword">return</span> x + y;</span><br><span class="line">&#125;;</span><br><span class="line">➖➖➖➖➖➖➖➖➖接口定义函数的形状➖➖➖➖➖➖➖➖➖</span><br><span class="line">interface SearchFunc &#123;</span><br><span class="line">    (source: string, <span class="attr">subString</span>: string): boolean;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">let</span> mySearch: SearchFunc;</span><br><span class="line">mySearch = <span class="function"><span class="keyword">function</span>(<span class="params">source, subString</span>) </span>&#123;</span><br><span class="line">    <span class="keyword">return</span> source.search(subString) !== <span class="number">-1</span>;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">➖➖➖➖➖➖➖➖➖可选参数➖➖➖➖➖➖➖➖➖</span><br><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">buildName</span>(<span class="params">firstName: string, lastName?: string</span>) </span>&#123;</span><br><span class="line">    <span class="keyword">if</span> (lastName) &#123;</span><br><span class="line">        <span class="keyword">return</span> firstName + <span class="string">' '</span> + lastName;</span><br><span class="line">    &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">        <span class="keyword">return</span> firstName;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"><span class="keyword">let</span> tomcat = buildName(<span class="string">'Tom'</span>, <span class="string">'Cat'</span>);</span><br><span class="line"><span class="keyword">let</span> tom = buildName(<span class="string">'Tom'</span>);</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">➖➖➖➖➖➖➖➖➖参数默认值➖➖➖➖➖➖➖➖➖</span><br><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">buildName</span>(<span class="params">firstName: string, lastName: string = <span class="string">'Cat'</span></span>) </span>&#123;</span><br><span class="line">    <span class="keyword">return</span> firstName + <span class="string">' '</span> + lastName;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">➖➖➖➖➖➖➖➖➖剩余参数➖➖➖➖➖➖➖➖➖</span><br><span class="line"><span class="comment">// rest 参数只能是最后一个参数，关于 rest 参数,是一个数组</span></span><br><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">push</span>(<span class="params">array: any[], ...items: any[]</span>) </span>&#123;</span><br><span class="line">    items.forEach(<span class="function"><span class="keyword">function</span>(<span class="params">item</span>) </span>&#123;</span><br><span class="line">        array.push(item);</span><br><span class="line">    &#125;);</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">let</span> a = [];</span><br><span class="line">push(a, <span class="number">1</span>, <span class="number">2</span>, <span class="number">3</span>);</span><br></pre></td></tr></table></figure>
<p><strong>错误的做法</strong></p>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line"><span class="comment">// 输入多余的（或者少于要求的）参数，是不被允许的：</span></span><br><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">sum</span>(<span class="params">x: number, y: number</span>): <span class="title">number</span> </span>&#123;</span><br><span class="line">    <span class="keyword">return</span> x + y;</span><br><span class="line">&#125;</span><br><span class="line">sum(<span class="number">1</span>, <span class="number">2</span>, <span class="number">3</span>); ❌</span><br><span class="line">sum(<span class="number">1</span>);❌</span><br><span class="line"></span><br><span class="line"><span class="comment">// 输入多余的（或者少于要求的）参数，是不被允许的：</span></span><br><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">sum</span>(<span class="params">x: number, y: number</span>): <span class="title">number</span> </span>&#123;</span><br><span class="line">    <span class="keyword">return</span> x + y;</span><br><span class="line">&#125;</span><br><span class="line">sum(<span class="number">1</span>, <span class="number">2</span>, <span class="number">3</span>);</span><br><span class="line"></span><br><span class="line"><span class="comment">// 可选参数后面不允许再出现必须参数了：</span></span><br><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">buildName</span>(<span class="params">firstName?: string, lastName: string</span>) </span>&#123;❌</span><br><span class="line">    <span class="keyword">if</span> (firstName) &#123;</span><br><span class="line">        <span class="keyword">return</span> firstName + <span class="string">' '</span> + lastName;</span><br><span class="line">    &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">        <span class="keyword">return</span> lastName;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"><span class="keyword">let</span> tomcat = buildName(<span class="string">'Tom'</span>, <span class="string">'Cat'</span>);</span><br><span class="line"><span class="keyword">let</span> tom = buildName(<span class="literal">undefined</span>, <span class="string">'Tom'</span>);</span><br></pre></td></tr></table></figure>
<h3 id="7-1-函数相关知识点梳理"><a href="#7-1-函数相关知识点梳理" class="headerlink" title="7.1 函数相关知识点梳理"></a>7.1 函数相关知识点梳理</h3><p><strong>四种声明方式：</strong></p>
<ul>
<li>通过<code>function</code></li>
<li>通过变量</li>
<li>通过接口</li>
<li>通过类型别名</li>
</ul>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line"><span class="comment">// 函数定义</span></span><br><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">add1</span>(<span class="params">x: number, y: number</span>) </span>&#123;</span><br><span class="line">    <span class="keyword">return</span> x + y</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">// 通过变量</span></span><br><span class="line"><span class="keyword">let</span> add2: <span class="function">(<span class="params">x: number, y: number</span>) =&gt;</span> number</span><br><span class="line"></span><br><span class="line"><span class="comment">// 通过类型别名</span></span><br><span class="line"><span class="keyword">let</span> add3 = <span class="function">(<span class="params">x: number, y: number</span>) =&gt;</span> number</span><br><span class="line"></span><br><span class="line"><span class="comment">// 通过类型别名</span></span><br><span class="line">interface add4 &#123;</span><br><span class="line">    (x: number, <span class="attr">y</span>: number): number</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<p><strong>用interface定义函数和用type定义函数有区别?</strong></p>
<ul>
<li><code>type</code>：不是创建新的类型，只是为一个给定的类型起一个名字。<code>type</code>还可以进行联合、交叉等操作，引用起来更简洁</li>
<li><code>interface</code>：创建新的类型，接口之间还可以继承、声明合并</li>
<li>如果可能，建议优先使用 <code>interface</code>。</li>
<li>混合接口一般是为第三方类库写声明文件时会用到，很多类库名称可以直接当函数调用，也可以有些属性和方法。例子可以看一下<code>@types/jest/index.d.ts</code> 里面有一些混合接口。</li>
<li>用混合接口声明函数和用接口声明类的区别是，接口不能声明类的构造函数（既不带名称的函数），但混合接口可以，其他都一样。</li>
</ul>
<p><strong>函数重载</strong></p>
<p>函数名相同，返回类型不同</p>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">add8</span>(<span class="params">...rest: number[]</span>): <span class="title">number</span>;</span></span><br><span class="line"><span class="function"><span class="title">function</span> <span class="title">add8</span>(<span class="params">...rest: string[]</span>): <span class="title">string</span>;</span></span><br><span class="line"><span class="function"><span class="title">function</span> <span class="title">add8</span>(<span class="params">...rest: any[]</span>): <span class="title">any</span> </span>&#123;</span><br><span class="line">    <span class="keyword">let</span> first = rest[<span class="number">0</span>];</span><br><span class="line">    <span class="keyword">if</span>(<span class="keyword">typeof</span> first === <span class="string">'string'</span>) &#123;</span><br><span class="line">        <span class="keyword">return</span> rest.join(<span class="string">''</span>)</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">if</span>(<span class="keyword">typeof</span> first === <span class="string">'number'</span>) &#123;</span><br><span class="line">        <span class="keyword">return</span> rest.reduce(<span class="function">(<span class="params">pre, cur</span>) =&gt;</span> pre + cur)</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<h2 id="八、类型断言"><a href="#八、类型断言" class="headerlink" title="八、类型断言"></a>八、类型断言</h2><ul>
<li>有时候你会遇到这样的情况，你会比 <code>TypeScript</code> 更了解某个值的详细信息。 通常这会发生在你清楚地知道一个实体具有比它现有类型更确切的类型。</li>
<li>通过类型断言这种方式可以告诉编译器，“相信我，我知道自己在干什么”。 类型断言好比其它语言里的类型转换，但是不进行特殊的数据检查和解构。 它没有运行时的影响，只是在编译阶段起作用。 <code>TypeScript</code> 会假设你，程序员，已经进行了必须的检查。</li>
</ul>
<p>类型断言有两种形式。 其一是“尖括号”语法：</p>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line"><span class="keyword">let</span> someValue: any = <span class="string">'this is a string'</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">let</span> strLength: number = (<span class="xml"><span class="tag">&lt;<span class="name">string</span>&gt;</span>someValue).length</span></span><br></pre></td></tr></table></figure>
<blockquote>
<p>另一个为 <code>as</code> 语法：</p>
</blockquote>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line"><span class="keyword">let</span> someValue: any = <span class="string">'this is a string'</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">let</span> strLength: number = (someValue <span class="keyword">as</span> string).length</span><br></pre></td></tr></table></figure>
<blockquote>
<p>两种形式是等价的。 至于使用哪个大多数情况下是凭个人喜好；然而，当你在 <code>TypeScript</code> 里使用 <code>JSX</code> 时，只有<code>as</code> 语法断言是被允许</p>
</blockquote>
<p><strong>正确的做法</strong></p>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line"><span class="comment">// 可以使用类型断言，将 something 断言成 string</span></span><br><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">getLength</span>(<span class="params">something: string | number</span>): <span class="title">number</span> </span>&#123;</span><br><span class="line">    <span class="keyword">if</span> ((<span class="xml"><span class="tag">&lt;<span class="name">string</span>&gt;</span>something).length) &#123;</span></span><br><span class="line">        return (&lt;string&gt;something).length;</span><br><span class="line">    &#125; else &#123;</span><br><span class="line">        return something.toString().length;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<p><strong>错误的做法</strong></p>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line"><span class="comment">// 只能访问此联合类型的所有类型里共有的属性或方法</span></span><br><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">getLength</span>(<span class="params">something: string | number</span>): <span class="title">number</span> </span>&#123; ❌</span><br><span class="line">    <span class="keyword">return</span> something.length;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<h2 id="九、类型别名"><a href="#九、类型别名" class="headerlink" title="九、类型别名"></a>九、类型别名</h2><p><strong>正确的做法</strong></p>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line"><span class="comment">// 使用 type 创建类型别名,类型别名常用于联合类型</span></span><br><span class="line">type Name = string;</span><br><span class="line">type NameResolver = <span class="function"><span class="params">()</span> =&gt;</span> string;</span><br><span class="line">type NameOrResolver = Name | NameResolver;</span><br><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">getName</span>(<span class="params">n: NameOrResolver</span>): <span class="title">Name</span> </span>&#123;</span><br><span class="line">    <span class="keyword">if</span> (<span class="keyword">typeof</span> n === <span class="string">'string'</span>) &#123;</span><br><span class="line">        <span class="keyword">return</span> n;</span><br><span class="line">    &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">        <span class="keyword">return</span> n();</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<h2 id="十、枚举"><a href="#十、枚举" class="headerlink" title="十、枚举"></a>十、枚举</h2><p><strong>正确的做法</strong></p>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line"><span class="comment">// 枚举（Enum）类型用于取值被限定在一定范围内的场景，比如一周只能有七天	</span></span><br><span class="line"><span class="comment">// 枚举就是枚举值到枚举名进行反向映射</span></span><br><span class="line"></span><br><span class="line">enum Days &#123;Sun, Mon, Tue, Wed, Thu, Fri, Sat&#125;;</span><br><span class="line"><span class="built_in">console</span>.log(Days[<span class="string">"Sun"</span>]); <span class="comment">// 0</span></span><br><span class="line"><span class="built_in">console</span>.log(Days[<span class="number">0</span>]); <span class="comment">// 'Sun'</span></span><br><span class="line"></span><br><span class="line">enum Days &#123;Sun = <span class="number">7</span>, Mon = <span class="number">1</span>, Tue, Wed, Thu, Fri, Sat&#125;;</span><br><span class="line"><span class="built_in">console</span>.log(Days[<span class="string">"Sun"</span>]); <span class="comment">// 7</span></span><br></pre></td></tr></table></figure>
<h2 id="十一、类"><a href="#十一、类" class="headerlink" title="十一、类"></a>十一、类</h2><p><strong>正确的做法</strong></p>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line">➖➖➖➖➖➖➖➖➖类➖➖➖➖➖➖➖➖➖</span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">Animal</span> </span>&#123;</span><br><span class="line">    <span class="keyword">constructor</span>(name) &#123;</span><br><span class="line">        <span class="keyword">this</span>.name = name;</span><br><span class="line">    &#125;</span><br><span class="line">    sayHi() &#123;</span><br><span class="line">        <span class="keyword">return</span> <span class="string">`My name is <span class="subst">$&#123;<span class="keyword">this</span>.name&#125;</span>`</span>;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">let</span> a = <span class="keyword">new</span> Animal(<span class="string">'Jack'</span>);</span><br><span class="line"><span class="built_in">console</span>.log(a.sayHi()); <span class="comment">// My name is Jack</span></span><br><span class="line">➖➖➖➖➖➖➖➖➖继承➖➖➖➖➖➖➖➖➖</span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">Cat</span> <span class="keyword">extends</span> <span class="title">Animal</span> </span>&#123;</span><br><span class="line">    <span class="keyword">constructor</span>(name) &#123;</span><br><span class="line">        <span class="keyword">super</span>(name); <span class="comment">// 调用父类的 constructor(name)</span></span><br><span class="line">        <span class="built_in">console</span>.log(<span class="keyword">this</span>.name);</span><br><span class="line">    &#125;</span><br><span class="line">    sayHi() &#123;</span><br><span class="line">        <span class="keyword">return</span> <span class="string">'Meow, '</span> + <span class="keyword">super</span>.sayHi(); <span class="comment">// 调用父类的 sayHi()</span></span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">let</span> c = <span class="keyword">new</span> Cat(<span class="string">'Tom'</span>); <span class="comment">// Tom</span></span><br><span class="line"><span class="built_in">console</span>.log(c.sayHi()); <span class="comment">// Meow, My name is Tom</span></span><br><span class="line">➖➖➖➖➖➖➖➖➖存储器➖➖➖➖➖➖➖➖➖</span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">Animal</span> </span>&#123;</span><br><span class="line">    <span class="keyword">constructor</span>(name) &#123;</span><br><span class="line">        <span class="keyword">this</span>.name = name;</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">get</span> name() &#123;</span><br><span class="line">        <span class="keyword">return</span> <span class="string">'Jack'</span>;</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">set</span> name(value) &#123;</span><br><span class="line">        <span class="built_in">console</span>.log(<span class="string">'setter: '</span> + value);</span><br><span class="line">        <span class="keyword">this</span>.name = value;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">let</span> a = <span class="keyword">new</span> Animal(<span class="string">'Kitty'</span>); <span class="comment">// setter: Kitty</span></span><br><span class="line">a.name = <span class="string">'Tom'</span>; <span class="comment">// setter: Tom</span></span><br><span class="line"><span class="built_in">console</span>.log(a.name); <span class="comment">// Jack</span></span><br><span class="line">➖➖➖➖➖➖➖➖➖静态方法➖➖➖➖➖➖➖➖➖</span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">Animal</span> </span>&#123;</span><br><span class="line">    <span class="keyword">static</span> isAnimal(a) &#123;</span><br><span class="line">        <span class="keyword">return</span> a <span class="keyword">instanceof</span> Animal;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">let</span> a = <span class="keyword">new</span> Animal(<span class="string">'Jack'</span>);</span><br><span class="line">Animal.isAnimal(a); <span class="comment">// true</span></span><br><span class="line"><span class="comment">// 只能通过类名调用</span></span><br><span class="line">a.isAnimal(a); <span class="comment">// TypeError: a.isAnimal is not a function ❌</span></span><br><span class="line">➖➖➖➖➖➖➖➖➖抽象类➖➖➖➖➖➖➖➖➖</span><br><span class="line"><span class="comment">// 只能被继承，不能被实例化</span></span><br><span class="line">abstract <span class="class"><span class="keyword">class</span> <span class="title">Animal</span> </span>&#123;</span><br><span class="line">  eat()&#123;</span><br><span class="line">    <span class="built_in">console</span>.log(<span class="string">'eat'</span>)</span><br><span class="line">  &#125;</span><br><span class="line">  abstract sleep(): <span class="keyword">void</span></span><br><span class="line">&#125;</span><br><span class="line"><span class="comment">// 子类必须实现抽象类的抽象方法</span></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">Dog</span> <span class="keyword">extends</span> <span class="title">Animal</span> </span>&#123;</span><br><span class="line">    <span class="keyword">constructor</span>(name: string) &#123;</span><br><span class="line">        <span class="keyword">super</span>()</span><br><span class="line">        <span class="keyword">this</span>.name = name</span><br><span class="line">    &#125;</span><br><span class="line">    name: string;</span><br><span class="line">    run() &#123;&#125;</span><br><span class="line">    sleep() &#123;</span><br><span class="line">        <span class="built_in">console</span>.log(<span class="string">'dog sleep'</span>)</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">let</span> dog = <span class="keyword">new</span> Dog(<span class="string">'wang'</span>)</span><br><span class="line">dog.eat()</span><br></pre></td></tr></table></figure>
<h3 id="11-1类与接口的关系"><a href="#11-1类与接口的关系" class="headerlink" title="11.1类与接口的关系"></a>11.1类与接口的关系</h3><figure class="highlight js"><table><tr><td class="code"><pre><span class="line">interface Human &#123;</span><br><span class="line">    name: string;</span><br><span class="line">    eat(): <span class="keyword">void</span>;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">// 实现接口中声明的属性</span></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">Person</span> <span class="title">implements</span> <span class="title">Human</span> </span>&#123;</span><br><span class="line">    <span class="keyword">constructor</span>(name: string) &#123;</span><br><span class="line">        <span class="keyword">this</span>.name = name</span><br><span class="line">    &#125;</span><br><span class="line">    name: string;</span><br><span class="line">    eat() &#123;&#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line"><span class="comment">// 接口可以像类一样实现继承</span></span><br><span class="line">interface Man extends Human &#123;</span><br><span class="line">    run(): voild</span><br><span class="line">&#125;</span><br><span class="line">interface Child &#123;</span><br><span class="line">    cry(): voild</span><br><span class="line">&#125;</span><br><span class="line">interface Boy extends Man,Child &#123;&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">// 添加被继承过来的属性</span></span><br><span class="line"><span class="keyword">let</span> body: Boy = &#123;</span><br><span class="line">    name: <span class="string">'xx'</span>,</span><br><span class="line">    run() &#123;&#125;,</span><br><span class="line">    eat() &#123;&#125;,</span><br><span class="line">    cry() &#123;&#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<h2 id="十二、public-private-和-protected"><a href="#十二、public-private-和-protected" class="headerlink" title="十二、public private 和 protected"></a>十二、public private 和 protected</h2><ul>
<li><code>public</code> 修饰的属性或方法是公有的，可以在任何地方被访问到，默认所有的属性和方法都是 <code>public</code> 的</li>
<li><code>private</code> 修饰的属性或方法是私有的，不能在声明它的类的外部访问</li>
<li><code>protected</code> 修饰的属性或方法是受保护的，它和 <code>private</code> 类似，区别是它在子类中也是允许被访问的</li>
</ul>
<h2 id="十三、泛型"><a href="#十三、泛型" class="headerlink" title="十三、泛型"></a>十三、泛型</h2><blockquote>
<p>更多详情 <a href="http://blog.poetries.top/ts-axios/chapter2/generic.html">http://blog.poetries.top/ts-axios/chapter2/generic.html</a></p>
</blockquote>
<blockquote>
<p>泛型就是解决 类 接口 方法的复用性、以及对不特定数据类型的支持。<strong>泛型理解为代表类型的参数，只是另一个维度的参数</strong></p>
</blockquote>
<p><strong>正确的做法</strong></p>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line"><span class="comment">//只能返回string类型的数据</span></span><br><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">getData</span>(<span class="params">value:string</span>):<span class="title">string</span></span>&#123;</span><br><span class="line">  <span class="keyword">return</span> value;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">//同时返回 string类型 和number类型  （代码冗余）</span></span><br><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">getData1</span>(<span class="params">value:string</span>):<span class="title">string</span></span>&#123;</span><br><span class="line">  <span class="keyword">return</span> value;</span><br><span class="line">&#125;</span><br><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">getData2</span>(<span class="params">value:number</span>):<span class="title">number</span></span>&#123;</span><br><span class="line">  <span class="keyword">return</span> value;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;使用泛型后就可以解决这个问题</span><br><span class="line"><span class="comment">// T表示泛型，具体什么类型是调用这个方法的时候决定的</span></span><br><span class="line"><span class="comment">// 表示参数是什么类型就返回什么类型~~~</span></span><br><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">getData</span>&lt;<span class="title">T</span>&gt;(<span class="params">value:T</span>):<span class="title">T</span></span>&#123;</span><br><span class="line">  <span class="keyword">return</span> value;</span><br><span class="line">&#125;</span><br><span class="line">getData&lt;number&gt;(<span class="number">123</span>);</span><br><span class="line">getData&lt;string&gt;(<span class="string">'1214231'</span>);</span><br><span class="line"></span><br><span class="line"><span class="comment">// 定义接口</span></span><br><span class="line">interface ConfigFn&#123;</span><br><span class="line">    &lt;T&gt;(value:T):T;</span><br><span class="line">&#125;</span><br><span class="line"><span class="keyword">var</span> getData:ConfigFn=<span class="function"><span class="keyword">function</span>&lt;<span class="title">T</span>&gt;(<span class="params">value:T</span>):<span class="title">T</span></span>&#123;</span><br><span class="line">  <span class="keyword">return</span> value;</span><br><span class="line">&#125;</span><br><span class="line">getData&lt;string&gt;(<span class="string">'张三'</span>);</span><br><span class="line">getData&lt;string&gt;(<span class="number">1243</span>);  <span class="comment">//错误</span></span><br></pre></td></tr></table></figure>
<h3 id="13-1-泛型函数和接口"><a href="#13-1-泛型函数和接口" class="headerlink" title="13.1 泛型函数和接口"></a>13.1 泛型函数和接口</h3><figure class="highlight js"><table><tr><td class="code"><pre><span class="line"><span class="comment">// 这两个等价的，使用时无需指定类型</span></span><br><span class="line">type Log = <span class="xml"><span class="tag">&lt;<span class="name">T</span>&gt;</span>(value: T) =&gt; T;</span></span><br><span class="line"></span><br><span class="line"><span class="xml">// 只约束改成员</span></span><br><span class="line"><span class="xml">interface Log &#123;</span></span><br><span class="line">  &lt;T&gt;(value: T):T</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">// 这两个等价的，使用时必须指定类型</span><br><span class="line">type Log&lt;T&gt; = (value: T) =&gt; T;</span><br><span class="line"></span><br><span class="line">// 约束接口的所有成员</span><br><span class="line">interface Log&lt;T&gt; &#123;</span><br><span class="line">  (value: T):T</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<h3 id="13-2-泛型类与泛型约束"><a href="#13-2-泛型类与泛型约束" class="headerlink" title="13.2 泛型类与泛型约束"></a>13.2 泛型类与泛型约束</h3><figure class="highlight js"><table><tr><td class="code"><pre><span class="line"><span class="comment">// 把泛型放到类的后面，就可以约束所有成员</span></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">Log</span>&lt;<span class="title">T</span>&gt; </span>&#123;</span><br><span class="line">    run(value: T) &#123;</span><br><span class="line">        <span class="keyword">return</span> value</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="comment">// 不能约束静态成员</span></span><br><span class="line">   <span class="comment">// static eat() // 报错</span></span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">// 实例化类 传入类型</span></span><br><span class="line"><span class="keyword">let</span> log1 = <span class="keyword">new</span> Log&lt;number&gt;()</span><br><span class="line">log1.run(<span class="number">1</span>)</span><br><span class="line"></span><br><span class="line"><span class="comment">// 不指定类型参数传任意都允许</span></span><br><span class="line"><span class="keyword">let</span> log2 = <span class="keyword">new</span> Log()</span><br><span class="line">log2.run(<span class="string">'1'</span>)</span><br></pre></td></tr></table></figure>
<p><strong>类型约束</strong></p>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line">interface Length &#123;</span><br><span class="line">    length: number</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">// T继承了接口 约束了不是任意类型都可传。传入的参数必须有length属性</span></span><br><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">log</span>&lt;<span class="title">T</span> <span class="title">extends</span> <span class="title">Length</span>&gt;(<span class="params">value: T</span>): <span class="title">T</span> </span>&#123;</span><br><span class="line">    <span class="built_in">console</span>.log(value, value.length)</span><br><span class="line">    <span class="keyword">return</span> value</span><br><span class="line">&#125;</span><br><span class="line"><span class="comment">// 如数组、字符串、对象都有length属性</span></span><br><span class="line">log([<span class="number">1</span>])</span><br><span class="line">log(<span class="string">'1'</span>)</span><br><span class="line">log(&#123;<span class="attr">a</span>:<span class="number">1</span>&#125;)</span><br></pre></td></tr></table></figure>
<ul>
<li>函数和类可以轻松支持多种类型，增强程序的扩展性</li>
<li>不必写多条函数重载</li>
<li>灵活控制类型之间的约束</li>
</ul>
<p><strong>对象属性约束</strong></p>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line"><span class="comment">// 泛型约束对象中的属性</span></span><br><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">getProp</span>&lt;<span class="title">T</span>,<span class="title">K</span> <span class="title">extends</span> <span class="title">keyof</span> <span class="title">T</span>&gt;(<span class="params">obj:T,key: K</span>) </span>&#123;</span><br><span class="line">    <span class="keyword">return</span> obj[key]</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<h2 id="十四、类型检查机制"><a href="#十四、类型检查机制" class="headerlink" title="十四、类型检查机制"></a>十四、类型检查机制</h2><h3 id="14-1-类型检查机制"><a href="#14-1-类型检查机制" class="headerlink" title="14.1 类型检查机制"></a>14.1 类型检查机制</h3><blockquote>
<p>编译器在做类型检查时，秉承的一些原则，表现出的一些行为</p>
</blockquote>
<p>作用：辅助开发，提高开发效率</p>
<ul>
<li>类型推断</li>
<li>类型兼容性</li>
<li>类型保护</li>
</ul>
<blockquote>
<p>所谓类型推断：不需要指定变量的类型（函数的返回值类型），TS可以根据某些规则自动的为其推断出一个类型</p>
</blockquote>
<ul>
<li>基础类型推断</li>
<li>最佳通用类型推断</li>
<li>上下文类型推断</li>
</ul>
<blockquote>
<p>基础类型推断，从右向左。但是有些是从左向右推断</p>
</blockquote>
<p>如事件</p>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line"><span class="comment">// ts 根据onkeydown推断出类型</span></span><br><span class="line"><span class="built_in">window</span>.onkeydown = <span class="function"><span class="params">event</span>=&gt;</span>&#123;</span><br><span class="line">    <span class="built_in">console</span>.log(event)</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<blockquote>
<p>通过类型断言阻断TS的类型推断</p>
</blockquote>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line">interface Foo &#123;</span><br><span class="line">    bar: number</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">//let foo = &#123;&#125; as Foo</span></span><br><span class="line"><span class="comment">//foo.bar = 1</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">let</span> foo: Foo = &#123;</span><br><span class="line">    bar: <span class="number">1</span></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<h3 id="14-2-类型保护机制"><a href="#14-2-类型保护机制" class="headerlink" title="14.2 类型保护机制"></a>14.2 类型保护机制</h3><blockquote>
<p>联合类型适合于那些值可以为不同类型的情况。 但当我们想确切地了解是否为 Fish 或者是 Bird 时怎么办？ JavaScript 里常用来区分这 2 个可能值的方法是检查成员是否存在。如之前提及的，我们只能访问联合类型中共同拥有的成员</p>
</blockquote>
<p><strong>不同的判断方法有不同的使用场景：</strong></p>
<ul>
<li><code>typeof</code>：判断一个变量的类型</li>
<li><code>instanceof</code>：判断一个实例是否属于某个类</li>
<li><code>in</code>：判断一个属性是否属于某个对象</li>
<li>类型保护函数：某些判断可能不是一条语句能够搞定的，需要更多复杂的逻辑，适合封装到一个函数内</li>
</ul>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">getLanguage</span>(<span class="params">type: Type</span>) </span>&#123;</span><br><span class="line">    <span class="keyword">let</span> lang = type === type.Strong ? <span class="keyword">new</span> Java(): <span class="keyword">new</span> Javascript()</span><br><span class="line">    </span><br><span class="line">    <span class="comment">// 类型保护instanceof</span></span><br><span class="line">    <span class="keyword">if</span>(lang <span class="keyword">instanceof</span> Java)&#123;</span><br><span class="line">        lang.hellJava()</span><br><span class="line">    &#125;<span class="keyword">else</span> &#123;</span><br><span class="line">        lang.hellJavaScript()</span><br><span class="line">    &#125;</span><br><span class="line">    </span><br><span class="line">    <span class="comment">// in</span></span><br><span class="line">    <span class="keyword">if</span>(<span class="string">'java'</span> <span class="keyword">in</span> lang) &#123;</span><br><span class="line">        lang.hellJava()</span><br><span class="line">    &#125;<span class="keyword">else</span> &#123;</span><br><span class="line">        lang.hellJavaScript()</span><br><span class="line">    &#125;</span><br><span class="line">    </span><br><span class="line">    <span class="comment">// 类型保护函数方式</span></span><br><span class="line">    <span class="keyword">if</span>(isJava(lang)) &#123;</span><br><span class="line">        lang.hellJava()</span><br><span class="line">    &#125;<span class="keyword">else</span> &#123;</span><br><span class="line">        lang.hellJavaScript()</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">// 创建一种类型保护函数</span></span><br><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">isJava</span>(<span class="params">lang: Java | Javascript</span>): <span class="title">lang</span> <span class="title">is</span> <span class="title">Java</span> </span>&#123;</span><br><span class="line">    <span class="comment">// 类型断言</span></span><br><span class="line">    <span class="keyword">return</span> (lang <span class="keyword">as</span> Java).lang.helloJava !== <span class="literal">undefined</span></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line"><span class="keyword">let</span> pet = getSmallPet()</span><br><span class="line"></span><br><span class="line"><span class="comment">// 每一个成员访问都会报错</span></span><br><span class="line"><span class="keyword">if</span> (pet.swim) &#123;</span><br><span class="line">  pet.swim()</span><br><span class="line">&#125; <span class="keyword">else</span> <span class="keyword">if</span> (pet.fly) &#123;</span><br><span class="line">  pet.fly()</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<p>为了让这段代码工作，我们要使用类型断言</p>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line"><span class="keyword">let</span> pet = getSmallPet()</span><br><span class="line"></span><br><span class="line"><span class="keyword">if</span> ((pet <span class="keyword">as</span> Fish).swim) &#123;</span><br><span class="line">  (pet <span class="keyword">as</span> Fish).swim()</span><br><span class="line">&#125; <span class="keyword">else</span> &#123;</span><br><span class="line">  (pet <span class="keyword">as</span> Bird).fly()</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<h4 id="14-2-1-用户自定义的类型保护"><a href="#14-2-1-用户自定义的类型保护" class="headerlink" title="14.2.1 用户自定义的类型保护"></a>14.2.1 用户自定义的类型保护</h4><ul>
<li>这里可以注意到我们不得不多次使用类型断言。如果我们一旦检查过类型，就能在之后的每个分支里清楚地知道 <code>pet</code> 的类型的话就好了。</li>
<li><code>TypeScript</code> 里的类型保护机制让它成为了现实。 类型保护就是一些表达式，它们会在运行时检查以确保在某个作用域里的类型。定义一个类型保护，我们只要简单地定义一个函数，它的返回值是一个类型谓词</li>
</ul>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">isFish</span>(<span class="params">pet: Fish | Bird</span>): <span class="title">pet</span> <span class="title">is</span> <span class="title">Fish</span> </span>&#123;</span><br><span class="line">  <span class="keyword">return</span> (pet <span class="keyword">as</span> Fish).swim !== <span class="literal">undefined</span></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<ul>
<li>在这个例子里，<code>pet is Fish</code> 就是类型谓词。谓词为 <code>parameterName is Type</code> 这种形式， <code>parameterName</code> 必须是来自于当前函数签名里的一个参数名。</li>
<li>每当使用一些变量调用 <code>isFish</code> 时，TypeScript 会将变量缩减为那个具体的类型</li>
</ul>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line"><span class="keyword">if</span> (isFish(pet)) &#123;</span><br><span class="line">  pet.swim()</span><br><span class="line">&#125;</span><br><span class="line"><span class="keyword">else</span> &#123;</span><br><span class="line">  pet.fly()</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<blockquote>
<p>注意 TypeScript 不仅知道在 <code>if</code> 分支里 <code>pet</code> 是 <code>Fish</code> 类型；它还清楚在<code>else</code> 分支里，一定不是 <code>Fish</code>类型而是 <code>Bird</code> 类型</p>
</blockquote>
<h4 id="14-2-2-typeof-类型保护"><a href="#14-2-2-typeof-类型保护" class="headerlink" title="14.2.2 typeof 类型保护"></a>14.2.2 typeof 类型保护</h4><p>我们可以像下面这样利用类型断言来写</p>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">isNumber</span> (<span class="params">x: any</span>):<span class="title">x</span> <span class="title">is</span> <span class="title">string</span> </span>&#123;</span><br><span class="line">  <span class="keyword">return</span> <span class="keyword">typeof</span> x === <span class="string">'number'</span></span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">isString</span> (<span class="params">x: any</span>): <span class="title">x</span> <span class="title">is</span> <span class="title">string</span> </span>&#123;</span><br><span class="line">  <span class="keyword">return</span> <span class="keyword">typeof</span> x === <span class="string">'string'</span></span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">padLeft</span> (<span class="params">value: string, padding: string | number</span>) </span>&#123;</span><br><span class="line">  <span class="keyword">if</span> (isNumber(padding)) &#123;</span><br><span class="line">    <span class="keyword">return</span> <span class="built_in">Array</span>(padding + <span class="number">1</span>).join(<span class="string">' '</span>) + value</span><br><span class="line">  &#125;</span><br><span class="line">  <span class="keyword">if</span> (isString(padding)) &#123;</span><br><span class="line">    <span class="keyword">return</span> padding + value</span><br><span class="line">  &#125;</span><br><span class="line">  <span class="keyword">throw</span> <span class="keyword">new</span> <span class="built_in">Error</span>(<span class="string">`Expected string or number, got '<span class="subst">$&#123;padding&#125;</span>'.`</span>)</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<blockquote>
<p>然而，你必须要定义一个函数来判断类型是否是原始类型，但这并不必要。其实我们不必将 <code>typeof x === &#39;number&#39;</code>抽象成一个函数，因为 TypeScript 可以将它识别为一个类型保护。 也就是说我们可以直接在代码里检查类型了</p>
</blockquote>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">padLeft</span> (<span class="params">value: string, padding: string | number</span>) </span>&#123;</span><br><span class="line">  <span class="keyword">if</span> (<span class="keyword">typeof</span> padding === <span class="string">'number'</span>) &#123;</span><br><span class="line">    <span class="keyword">return</span> <span class="built_in">Array</span>(padding + <span class="number">1</span>).join(<span class="string">' '</span>) + value</span><br><span class="line">  &#125;</span><br><span class="line">  <span class="keyword">if</span> (<span class="keyword">typeof</span> padding === <span class="string">'string'</span>) &#123;</span><br><span class="line">    <span class="keyword">return</span> padding + value</span><br><span class="line">  &#125;</span><br><span class="line">  <span class="keyword">throw</span> <span class="keyword">new</span> <span class="built_in">Error</span>(<span class="string">`Expected string or number, got '<span class="subst">$&#123;padding&#125;</span>'.`</span>)</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<blockquote>
<p>这些 <code>typeof</code> 类型保护只有两种形式能被识别：<code>typeof v === &quot;typename&quot;</code> 和 <code>typeof v !== &quot;typename&quot;</code>， <code>&quot;typename&quot;</code>必须是 <code>&quot;number&quot;</code>， <code>&quot;string&quot;</code>，<code>&quot;boolean&quot;</code> 或 <code>&quot;symbol&quot;</code>。 但是 TypeScript 并不会阻止你与其它字符串比较，只是 TypeScript 不会把那些表达式识别为类型保护。</p>
</blockquote>
<h4 id="14-2-3-instanceof-类型保护"><a href="#14-2-3-instanceof-类型保护" class="headerlink" title="14.2.3 instanceof 类型保护"></a>14.2.3 instanceof 类型保护</h4><ul>
<li>如果你已经阅读了 <code>typeof</code> 类型保护并且对 JavaScript 里的 <code>instanceof</code> 操作符熟悉的话，你可能已经猜到了这节要讲的内容。</li>
<li><code>instanceof</code> 类型保护是通过构造函数来细化类型的一种方式。我们把之前的例子做一个小小的改造：</li>
</ul>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">Bird</span> </span>&#123;</span><br><span class="line">  fly () &#123;</span><br><span class="line">    <span class="built_in">console</span>.log(<span class="string">'bird fly'</span>)</span><br><span class="line">  &#125;</span><br><span class="line"></span><br><span class="line">  layEggs () &#123;</span><br><span class="line">    <span class="built_in">console</span>.log(<span class="string">'bird lay eggs'</span>)</span><br><span class="line">  &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">Fish</span> </span>&#123;</span><br><span class="line">  swim () &#123;</span><br><span class="line">    <span class="built_in">console</span>.log(<span class="string">'fish swim'</span>)</span><br><span class="line">  &#125;</span><br><span class="line"></span><br><span class="line">  layEggs () &#123;</span><br><span class="line">    <span class="built_in">console</span>.log(<span class="string">'fish lay eggs'</span>)</span><br><span class="line">  &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">getRandomPet</span> (<span class="params"></span>) </span>&#123;</span><br><span class="line">  <span class="keyword">return</span> <span class="built_in">Math</span>.random() &gt; <span class="number">0.5</span> ? <span class="keyword">new</span> Bird() : <span class="keyword">new</span> Fish()</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">let</span> pet = getRandomPet()</span><br><span class="line"></span><br><span class="line"><span class="keyword">if</span> (pet <span class="keyword">instanceof</span> Bird) &#123;</span><br><span class="line">  pet.fly()</span><br><span class="line">&#125;</span><br><span class="line"><span class="keyword">if</span> (pet <span class="keyword">instanceof</span> Fish) &#123;</span><br><span class="line">  pet.swim()</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<h2 id="十五、高级类型"><a href="#十五、高级类型" class="headerlink" title="十五、高级类型"></a>十五、高级类型</h2><h3 id="15-1-交叉类型（取并集）"><a href="#15-1-交叉类型（取并集）" class="headerlink" title="15.1 交叉类型（取并集）"></a>15.1 交叉类型（取并集）</h3><blockquote>
<p>交叉类型是将多个类型合并为一个类型。这让我们可以把现有的多种类型叠加到一起成为一种类型，它包含了所需的所有类型的特性。 例如，<code>Person &amp; Loggable</code> 同时是 <code>Person</code> 和 <code>Loggable</code>。就是说这个类型的对象同时拥有了这两种类型的成员。</p>
</blockquote>
<blockquote>
<p>我们大多是在混入（mixins）或其它不适合典型面向对象模型的地方看到交叉类型的使用。 （在 JavaScript里发生这种情况的场合很多！）下面是如何创建混入的一个简单例子</p>
</blockquote>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">extend</span>&lt;<span class="title">T</span>, <span class="title">U</span>&gt; (<span class="params">first: T, second: U</span>): <span class="title">T</span> &amp; <span class="title">U</span> </span>&#123;</span><br><span class="line">  <span class="keyword">let</span> result = &#123;&#125; <span class="keyword">as</span> T &amp; U</span><br><span class="line">  <span class="keyword">for</span> (<span class="keyword">let</span> id <span class="keyword">in</span> first) &#123;</span><br><span class="line">    result[id] = first[id] <span class="keyword">as</span> any</span><br><span class="line">  &#125;</span><br><span class="line">  <span class="keyword">for</span> (<span class="keyword">let</span> id <span class="keyword">in</span> second) &#123;</span><br><span class="line">    <span class="keyword">if</span> (!result.hasOwnProperty(id)) &#123;</span><br><span class="line">      result[id] = second[id] <span class="keyword">as</span> any</span><br><span class="line">    &#125;</span><br><span class="line">  &#125;</span><br><span class="line">  <span class="keyword">return</span> result</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">Person</span> </span>&#123;</span><br><span class="line">  <span class="keyword">constructor</span> (public name: string) &#123;</span><br><span class="line">  &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">interface Loggable &#123;</span><br><span class="line">  log (): <span class="keyword">void</span></span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">ConsoleLogger</span> <span class="title">implements</span> <span class="title">Loggable</span> </span>&#123;</span><br><span class="line">  log () &#123;</span><br><span class="line">    <span class="comment">// ...</span></span><br><span class="line">  &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">var</span> jim = extend(<span class="keyword">new</span> Person(<span class="string">'Jim'</span>), <span class="keyword">new</span> ConsoleLogger())</span><br><span class="line"><span class="keyword">var</span> n = jim.name</span><br><span class="line">jim.log()</span><br></pre></td></tr></table></figure>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line">interface DogInterface &#123;</span><br><span class="line">    run(): <span class="keyword">void</span></span><br><span class="line">&#125;</span><br><span class="line">interface CatInterface &#123;</span><br><span class="line">    jump(): <span class="keyword">void</span></span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">// pet 具备两个接口的所有方法</span></span><br><span class="line"><span class="keyword">let</span> pet: DogInterface &amp; CatInterface = &#123;</span><br><span class="line">    run() &#123;&#125;,</span><br><span class="line">    jump() &#123;&#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">// 联合类型</span></span><br><span class="line"><span class="keyword">let</span> a: number | string = <span class="number">1</span></span><br><span class="line"><span class="keyword">let</span> b: <span class="string">'a'</span> | <span class="string">'b'</span> | <span class="string">'c'</span> <span class="comment">// 字面量联合类型</span></span><br><span class="line"><span class="keyword">let</span> c: <span class="number">1</span> | <span class="number">2</span> | <span class="number">3</span> <span class="comment">// 数字联合类型</span></span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">Dog</span> <span class="title">implements</span> <span class="title">DogInterface</span> </span>&#123;</span><br><span class="line">    run() &#123;&#125;</span><br><span class="line">    eat() &#123;&#125;</span><br><span class="line">&#125;</span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">Cat</span>  <span class="title">implements</span> <span class="title">CatInterface</span> </span>&#123;</span><br><span class="line">    jump() &#123;&#125;</span><br><span class="line">    eat() &#123;&#125;</span><br><span class="line">&#125;</span><br><span class="line">enum Master &#123; Boy, Girl &#125;</span><br><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">getPet</span>(<span class="params">master: Master</span>) </span>&#123;</span><br><span class="line">    <span class="keyword">let</span> pet = master === Master.Boy ? <span class="keyword">new</span> Dog() : <span class="keyword">new</span> Cat();</span><br><span class="line">    <span class="comment">// pet.run()</span></span><br><span class="line">    <span class="comment">// pet.jump()</span></span><br><span class="line">    pet.eat()</span><br><span class="line">    <span class="keyword">return</span> pet</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">interface Square &#123;</span><br><span class="line">    kind: <span class="string">"square"</span>;</span><br><span class="line">    size: number;</span><br><span class="line">&#125;</span><br><span class="line">interface Rectangle &#123;</span><br><span class="line">    kind: <span class="string">"rectangle"</span>;</span><br><span class="line">    width: number;</span><br><span class="line">    height: number;</span><br><span class="line">&#125;</span><br><span class="line">interface Circle &#123;</span><br><span class="line">    kind: <span class="string">"circle"</span>;</span><br><span class="line">    radius: number;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">type Shape = Square | Rectangle | Circle</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">area</span>(<span class="params">s: Shape</span>) </span>&#123;</span><br><span class="line">    <span class="keyword">switch</span> (s.kind) &#123;</span><br><span class="line">        <span class="keyword">case</span> <span class="string">"square"</span>:</span><br><span class="line">            <span class="keyword">return</span> s.size * s.size;</span><br><span class="line">        <span class="keyword">case</span> <span class="string">"rectangle"</span>:</span><br><span class="line">            <span class="keyword">return</span> s.height * s.width;</span><br><span class="line">        <span class="keyword">case</span> <span class="string">'circle'</span>:</span><br><span class="line">            <span class="keyword">return</span> <span class="built_in">Math</span>.PI * s.radius ** <span class="number">2</span></span><br><span class="line">        <span class="keyword">default</span>:</span><br><span class="line">            <span class="keyword">return</span> <span class="function">(<span class="params">(e: never</span>) =&gt;</span> &#123;<span class="keyword">throw</span> <span class="keyword">new</span> <span class="built_in">Error</span>(e)&#125;)(s)</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"><span class="built_in">console</span>.log(area(&#123;<span class="attr">kind</span>: <span class="string">'circle'</span>, <span class="attr">radius</span>: <span class="number">1</span>&#125;))</span><br></pre></td></tr></table></figure>
<h3 id="15-2-索引类型"><a href="#15-2-索引类型" class="headerlink" title="15.2 索引类型"></a>15.2 索引类型</h3><figure class="highlight js"><table><tr><td class="code"><pre><span class="line"><span class="keyword">let</span> obj = &#123;</span><br><span class="line">    a: <span class="number">1</span>,</span><br><span class="line">    b: <span class="number">2</span>,</span><br><span class="line">    c: <span class="number">3</span></span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">// function getValues(obj: any, keys: string[]) &#123;</span></span><br><span class="line"><span class="comment">//     return keys.map(key =&gt; obj[key])</span></span><br><span class="line"><span class="comment">// &#125;</span></span><br><span class="line">function getValues&lt;T, K extends keyof T&gt;(obj: T, keys: K[]): T[K][] &#123;</span><br><span class="line">    <span class="keyword">return</span> keys.map(<span class="function"><span class="params">key</span> =&gt;</span> obj[key])</span><br><span class="line">&#125;</span><br><span class="line"><span class="built_in">console</span>.log(getValues(obj, [<span class="string">'a'</span>, <span class="string">'b'</span>]))</span><br><span class="line"><span class="comment">// console.log(getValues(obj, ['d', 'e']))</span></span><br><span class="line"></span><br><span class="line"><span class="comment">// keyof T</span></span><br><span class="line">interface Obj &#123;</span><br><span class="line">    a: number;</span><br><span class="line">    b: string;</span><br><span class="line">&#125;</span><br><span class="line"><span class="keyword">let</span> key: keyof Obj</span><br><span class="line"></span><br><span class="line"><span class="comment">// T[K]</span></span><br><span class="line"><span class="keyword">let</span> value: Obj[<span class="string">'a'</span>]</span><br><span class="line"></span><br><span class="line"><span class="comment">// T extends U</span></span><br></pre></td></tr></table></figure>
<h3 id="15-3-映射类型"><a href="#15-3-映射类型" class="headerlink" title="15.3 映射类型"></a>15.3 映射类型</h3><figure class="highlight js"><table><tr><td class="code"><pre><span class="line">interface Obj &#123;</span><br><span class="line">    a: string;</span><br><span class="line">    b: number;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">// 使得每个成员属性变为只读</span></span><br><span class="line">type ReadonlyObj = Readonly&lt;Obj&gt;</span><br><span class="line"></span><br><span class="line"><span class="comment">// 把一个接口属性变为可选</span></span><br><span class="line">type PartialObj = Partial&lt;Obj&gt;</span><br><span class="line"></span><br><span class="line"><span class="comment">// 抽取obj的子集</span></span><br><span class="line">type PickObj = Pick&lt;Obj, <span class="string">'a'</span> | <span class="string">'b'</span>&gt;</span><br><span class="line"></span><br><span class="line">type RecordObj = Record&lt;<span class="string">'x'</span> | <span class="string">'y'</span>, Obj&gt;</span><br></pre></td></tr></table></figure>
<h3 id="15-4-条件类型"><a href="#15-4-条件类型" class="headerlink" title="15.4 条件类型"></a>15.4 条件类型</h3><figure class="highlight js"><table><tr><td class="code"><pre><span class="line"><span class="comment">// T extends U ? X : Y</span></span><br><span class="line"></span><br><span class="line">type TypeName&lt;T&gt; =</span><br><span class="line">    T extends string ? <span class="string">"string"</span> :</span><br><span class="line">    T extends number ? <span class="string">"number"</span> :</span><br><span class="line">    T extends boolean ? <span class="string">"boolean"</span> :</span><br><span class="line">    T extends <span class="literal">undefined</span> ? <span class="string">"undefined"</span> :</span><br><span class="line">    T extends <span class="built_in">Function</span> ? <span class="string">"function"</span> :</span><br><span class="line">    <span class="string">"object"</span>;</span><br><span class="line">type T1 = TypeName&lt;string&gt;</span><br><span class="line">type T2 = TypeName&lt;string[]&gt;</span><br><span class="line"></span><br><span class="line"><span class="comment">// (A | B) extends U ? X : Y</span></span><br><span class="line"><span class="comment">// (A extends U ? X : Y) | (B extends U ? X : Y)</span></span><br><span class="line">type T3 = TypeName&lt;string | string[]&gt;</span><br><span class="line"></span><br><span class="line">type Diff&lt;T, U&gt; = T extends U ? never : T</span><br><span class="line">type T4 = Diff&lt;<span class="string">"a"</span> | <span class="string">"b"</span> | <span class="string">"c"</span>, <span class="string">"a"</span> | <span class="string">"e"</span>&gt;</span><br><span class="line"><span class="comment">// Diff&lt;"a", "a" | "e"&gt; | Diff&lt;"b", "a" | "e"&gt; | Diff&lt;"c", "a" | "e"&gt;</span></span><br><span class="line"><span class="comment">// never | "b" | "c"</span></span><br><span class="line"><span class="comment">// "b" | "c"</span></span><br><span class="line"></span><br><span class="line">type NotNull&lt;T&gt; = Diff&lt;T, <span class="literal">null</span> | <span class="literal">undefined</span>&gt;</span><br><span class="line">type T5 = NotNull&lt;string | number | <span class="literal">undefined</span> | <span class="literal">null</span>&gt;</span><br><span class="line"></span><br><span class="line"><span class="comment">// Exclude&lt;T, U&gt;</span></span><br><span class="line"><span class="comment">// NonNullable&lt;T&gt;</span></span><br><span class="line"></span><br><span class="line"><span class="comment">// Extract&lt;T, U&gt;</span></span><br><span class="line">type T6 = Extract&lt;<span class="string">"a"</span> | <span class="string">"b"</span> | <span class="string">"c"</span>, <span class="string">"a"</span> | <span class="string">"e"</span>&gt;</span><br><span class="line"></span><br><span class="line"><span class="comment">// ReturnType&lt;T&gt;</span></span><br><span class="line">type T8 = ReturnType&lt;<span class="function"><span class="params">()</span> =&gt;</span> string&gt;</span><br></pre></td></tr></table></figure>
<h3 id="15-5-联合类型"><a href="#15-5-联合类型" class="headerlink" title="15.5 联合类型"></a>15.5 联合类型</h3><blockquote>
<p>联合类型与交叉类型很有关联，但是使用上却完全不同。 偶尔你会遇到这种情况，一个代码库希望传入 <code>number</code> 或 <code>string</code> 类型的参数。 例如下面的函数</p>
</blockquote>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">padLeft</span>(<span class="params">value: string, padding: any</span>) </span>&#123;</span><br><span class="line">  <span class="keyword">if</span> (<span class="keyword">typeof</span> padding === <span class="string">'number'</span>) &#123;</span><br><span class="line">    <span class="keyword">return</span> <span class="built_in">Array</span>(padding + <span class="number">1</span>).join(<span class="string">' '</span>) + value</span><br><span class="line">  &#125;</span><br><span class="line">  <span class="keyword">if</span> (<span class="keyword">typeof</span> padding === <span class="string">'string'</span>) &#123;</span><br><span class="line">    <span class="keyword">return</span> padding + value</span><br><span class="line">  &#125;</span><br><span class="line">  <span class="keyword">throw</span> <span class="keyword">new</span> <span class="built_in">Error</span>(<span class="string">`Expected string or number, got '<span class="subst">$&#123;padding&#125;</span>'.`</span>)</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">padLeft(<span class="string">'Hello world'</span>, <span class="number">4</span>) <span class="comment">// returns "    Hello world"</span></span><br></pre></td></tr></table></figure>
<blockquote>
<p>padLeft 存在一个问题，padding 参数的类型指定成了 any。 这就是说我们可以传入一个既不是 number 也不是 string 类型的参数，但是 TypeScript 却不报错</p>
</blockquote>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line"><span class="keyword">let</span> indentedString = padLeft(<span class="string">'Hello world'</span>, <span class="literal">true</span>) <span class="comment">// 编译阶段通过，运行时报错</span></span><br></pre></td></tr></table></figure>
<blockquote>
<p>为了解决这个问题，我们可以使用 联合类型做为 <code>padding</code> 的参数</p>
</blockquote>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">padLeft</span>(<span class="params">value: string, padding: string | number</span>) </span>&#123;</span><br><span class="line">  <span class="comment">// ...</span></span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">let</span> indentedString = padLeft(<span class="string">'Hello world'</span>, <span class="literal">true</span>) <span class="comment">// 编译阶段报错</span></span><br></pre></td></tr></table></figure>
<ul>
<li>联合类型表示一个值可以是几种类型之一。我们用竖线（<code>|</code>）分隔每个类型，所以 <code>number | string</code> 表示一个值可以是 <code>number</code>或<code>string</code>。</li>
</ul>
<blockquote>
<p>如果一个值是联合类型，<strong>我们只能访问此联合类型的所有类型里共有的成员</strong></p>
</blockquote>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line">interface Bird &#123;</span><br><span class="line">  fly()</span><br><span class="line">  layEggs()</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">interface Fish &#123;</span><br><span class="line">  swim()</span><br><span class="line">  layEggs()</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">getSmallPet</span>(<span class="params"></span>): <span class="title">Fish</span> | <span class="title">Bird</span> </span>&#123;</span><br><span class="line">  <span class="comment">// ...</span></span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">let</span> pet = getSmallPet()</span><br><span class="line">pet.layEggs() <span class="comment">// okay</span></span><br><span class="line">pet.swim()    <span class="comment">// error</span></span><br></pre></td></tr></table></figure>
<blockquote>
<p>这里的联合类型可能有点复杂：如果一个值的类型是 <code>A | B</code>，我们能够确定的是它包含了 <code>A</code> 和 <code>B</code> 中共有的成员。这个例子里，Fish 具有一个 <code>swim</code> 方法，我们不能确定一个 <code>Bird | Fish</code>类型的变量是否有 <code>swim</code>方法。 如果变量在运行时是 Bird 类型，那么调用 <code>pet.swim()</code>就出错了</p>
</blockquote>
<h2 id="十六、初学者的困惑"><a href="#十六、初学者的困惑" class="headerlink" title="十六、初学者的困惑"></a>十六、初学者的困惑</h2><h3 id="16-1-如何优雅的声明类型"><a href="#16-1-如何优雅的声明类型" class="headerlink" title="16.1 如何优雅的声明类型"></a>16.1 如何优雅的声明类型</h3><h4 id="16-1-1-基础"><a href="#16-1-1-基础" class="headerlink" title="16.1.1 基础"></a>16.1.1 基础</h4><figure class="highlight js"><table><tr><td class="code"><pre><span class="line">interface Basic &#123;</span><br><span class="line">  num: number;</span><br><span class="line">  str: string | <span class="literal">null</span>;</span><br><span class="line">  bol?: boolean;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<blockquote>
<p>五种 JS 值类型就声明好了。那数组、函数呢？</p>
</blockquote>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line">interface Func &#123;</span><br><span class="line">  func(str: string): <span class="keyword">void</span>;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">interface Arr &#123;</span><br><span class="line">  str: string[];</span><br><span class="line">  mixed: <span class="built_in">Array</span>&lt;string | number&gt;;</span><br><span class="line">  fixedStructure: [string, number];</span><br><span class="line">  basics: Basic[];</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<blockquote>
<p>枚举类型也是很常用的，比如声明一个状态机的各个状态</p>
</blockquote>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line">enum Status &#123;</span><br><span class="line">  Draft,</span><br><span class="line">  Published</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">// 也可指定值</span></span><br><span class="line">enum Status &#123;</span><br><span class="line">  Draft = <span class="string">'Draft'</span>,</span><br><span class="line">  Published = <span class="string">'Published'</span></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<h4 id="16-1-2-糅合"><a href="#16-1-2-糅合" class="headerlink" title="16.1.2 糅合"></a>16.1.2 糅合</h4><p><strong>独立声明</strong></p>
<blockquote>
<p>一个 <code>ts</code> 文件只声明一个类型或者接口，文件名为需要暴露的类型名称，方便检索和管理</p>
</blockquote>
<p><strong>就近声明</strong></p>
<blockquote>
<p>当一个声明没有被外部引用或者依赖时，可以考虑就近放在使用的地方，典型的场景是 <code>React</code> 组件的 <code>Props</code> 和 <code>State</code> 的类型声明</p>
</blockquote>
<p><strong>按职责分组</strong></p>
<ul>
<li>在项目中，需要声明类型的可大致分为两类：一类是 <code>model</code>，也就是接口请求相关的，包括入参和出参；另一类是 <code>view</code>，界面渲染相关的。因此，我在 独立声明 的基础上，可以类型按照<code>model</code> 和 <code>view</code> 的维度进行分组，相互独立。</li>
<li>那么问题来了，如果是独立的类型声明的话，怎么把 model 的数据应用到 <code>view</code> 呢？ 可能你需要一个 <code>adapter</code> 来做类型的的转换：<code>DTOTypes</code> -&gt; <code>adapter</code> -&gt; <code>ViewTypes</code>, 完成类似于将接口中的字符串映射成枚举类型这之类的转换</li>
</ul>
<p><strong>any</strong></p>
<blockquote>
<p>当遇到确实解决不了的类型报错的时候，<code>as any</code> 能带给你不一样的快感，但是不建议使用啊</p>
</blockquote>
<h3 id="16-2-如何引用外部库"><a href="#16-2-如何引用外部库" class="headerlink" title="16.2 如何引用外部库"></a>16.2 如何引用外部库</h3><blockquote>
<p>在 <code>JS</code> 中，<code>npm</code> 上有丰富的海量的库帮我们完成日常的编码，可能并不是所有的库都能完全被应用到 <code>TS</code> 中，因为有些缺少类型声明</p>
</blockquote>
<p>比如，在 <code>TS</code> 中使用 <code>react</code>, 你会得到这样的一个类型检查错误：</p>
<p><img src="https://pic2.zhimg.com/80/v2-fdfb8e5f2be67d8c978e216254b80a9d_hd.jpg" alt></p>
<ul>
<li>因为 react 的库中并没有类型声明</li>
<li>现在比较通用的做法是，实现和类型实现独立成两个库，也就是你需要再安装类型声明的库: <code>@types/react</code></li>
<li>当遇到上述问题的时候，尝试安装一下 <code>@types/[package]</code></li>
<li>然而，并不是所有的库都有类型声明的实现，也会有很多不支持 TS 的存在，然而又必须得使用这个库的时候该怎么办？</li>
</ul>
<p><strong>自己写声明</strong></p>
<blockquote>
<p>以 <code>progressbar.js</code>为例，基本使用方法</p>
</blockquote>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line"><span class="keyword">import</span> * <span class="keyword">as</span> ProgressBar <span class="keyword">from</span> <span class="string">'progressbar.js'</span>;</span><br><span class="line"></span><br><span class="line"><span class="keyword">new</span> ProgressBar.Circle(<span class="keyword">this</span>.$progress, &#123;</span><br><span class="line">  strokeWidth: <span class="number">8</span>,</span><br><span class="line">  trailColor: <span class="string">'#e5e4e5'</span>,</span><br><span class="line">  trailWidth: <span class="number">8</span>,</span><br><span class="line">  easing: <span class="string">'easeInOut'</span></span><br><span class="line">&#125;);</span><br></pre></td></tr></table></figure>
<p>我们需要对库中暴露出的 api 去做声明，对上述例子做个分解：暴露了 Circle 类，Circle 构造函数包含两个参数，一个 HTMLElement，一个 options. OK</p>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line"><span class="comment">// 首先声明一下模块：</span></span><br><span class="line">declare <span class="built_in">module</span> <span class="string">'progressbar.js'</span> &#123;</span><br><span class="line">  <span class="comment">// 模块中暴露了 Circle 类</span></span><br><span class="line">  <span class="keyword">export</span> <span class="class"><span class="keyword">class</span> <span class="title">Circle</span> </span>&#123;</span><br><span class="line">    <span class="keyword">constructor</span>(container: HTMLElement, options: Options);</span><br><span class="line">  &#125;</span><br><span class="line"></span><br><span class="line">  // 构造函数的 Options 需要单独声明 </span><br><span class="line">  interface Options &#123;</span><br><span class="line">    easing?: string;</span><br><span class="line">    strokeWidth?: number;</span><br><span class="line">    trailColor?: string;</span><br><span class="line">    trailWidth?: number;</span><br><span class="line">  &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<blockquote>
<p>如此我们便完成了一个简单的声明，当然实际使用中的 API 肯定比上述情况复杂，根据使用情况，用了哪些 API 或者参数，就补充那些的声明即可</p>
</blockquote>
<h3 id="16-3-如何组织一个-TS-项目"><a href="#16-3-如何组织一个-TS-项目" class="headerlink" title="16.3 如何组织一个 TS 项目"></a>16.3 如何组织一个 TS 项目</h3><ul>
<li>TS 项目的目录组织上，跟 JS 项目一样，补充好 types 的声明就可以了</li>
<li>需要注意的是，将你希望对外暴露的能力相关的类型声明都暴露出去，不友好的声明会让接入你项目的人非常的痛苦，同时，在 package.json 中需要指定 type 的 path, 比如：”types”: “dist/types/index.d.ts”</li>
<li>另外，务必加上 tslint, 更规范的去用 TS 实现功能，对于入门而言尤为重要</li>
</ul>
<h3 id="16-4-TSX-和-JSX"><a href="#16-4-TSX-和-JSX" class="headerlink" title="16.4 TSX 和 JSX"></a>16.4 TSX 和 JSX</h3><ul>
<li>之前我们在用 <code>JavaScript</code> 写 <code>React</code> 时，对文件的扩展名没有什么特别的要求，<code>.js</code> 或者 <code>.jsx</code> 都行。</li>
<li>但在 <code>TypeScript</code> 中，如果你要使用 <code>JSX</code> 语法，就不能使用 <code>.ts</code>，必须使用 <code>.tsx</code>。如果你不知道，或者忘了这么做，那么你会在使用了 <code>JSX</code> 代码的地方收到类型报错，但代码本身怎么看都没有问题。这也是刚上手 <code>TypeScript + React</code> 时几乎每个人都会遇到的坑。</li>
<li>关于这一点，<code>TypeScript</code> 只是在官方教程的示例代码中直接用了 <code>*.tsx</code>，但并没有明确说明这一问题</li>
</ul>
<h3 id="16-5-变量的-Type-怎么找"><a href="#16-5-变量的-Type-怎么找" class="headerlink" title="16.5 变量的 Type 怎么找"></a>16.5 变量的 Type 怎么找</h3><ul>
<li>上手 <code>TypeScript</code> 之后很快我们就发现，即便是原生的 <code>DOM</code>、或是 <code>React</code> 的 <code>API</code>，也经常会要我们手动指定类型。但这些结构并不是简单的 <code>JavaScript</code>原始类型，在使用 <code>JavaScript</code> 编写相关代码时候由于没有这种需要，我们也没关心过这些东西的类型，突然问起来，还真不知道这些类型叫什么名字。</li>
<li>不光是这些标准类型，同样的问题在很多第三方的库中也会遇到，比如一些组件库会检查你传入的 <code>Props</code></li>
<li>在我看来，这中间其实缺少了一部分的文档，来指导新用户如何找到所需要的类型。既然社区没有提供，那就我来吧。</li>
<li>当然，让每个开发者都熟记所有的类型肯定是不现实的，总不能每接触一个新的库，就要去记一堆类型吧。放心，世界还是美好的，这种事情，当然是有方法的。</li>
<li>最直白的方法就是去看库的 <code>Types Definition</code>，也就是那些 <code>.*d.ts</code> 文件。如果你刚好有在用 <code>VS Code</code> 的话，有一个非常方便的操作：把鼠标移动到你想知道它类型的代码上（比如某个变量、某个函数调用，或是某个 JSX 标签、某个组件的 props），右键选择「Go to Definition」（或者光标选中后按 F12），就可以跳转到它的类型定义文件了。</li>
<li>如果你更习惯使用 VS Code 之外的编辑器，我相信时至今日，它们应该也都早就对 <code>TypeScript</code> 提供了支持。具体操作我不太熟悉，你可以自己探索下（我一直用 VS Code，其它的不太熟）</li>
<li>一般来说，这个操作可以直接把你带到你想要的地方，但考虑到类型是可以继承的，有时候一次跳转可能不太够，遇到这种情况，那就需要你随机应变一下，沿着继承关系多跳几次，直到找到你想要的内容。</li>
<li>对于不熟悉的类型，可以通过这个方法去寻找，慢慢熟悉以后，你会发现，一些常见的类型还是很好找的，稍微联想一下英文的表达方式，配合自动补全的提示，一般都不难找到</li>
</ul>
<h3 id="16-6-常见-Types-之-DOM"><a href="#16-6-常见-Types-之-DOM" class="headerlink" title="16.6 常见 Types 之 DOM"></a>16.6 常见 Types 之 DOM</h3><ul>
<li><code>TypeScript</code> 自带了一些基本的类型定义，包括 ECMAScript 和 DOM 的类型定义，所有你需要的类型都可以从这里找到。如果你想做一些「纯 TypeScript 开发」的话，有这些就够了</li>
<li>比如下面这张截图，就是对 <code>&lt;div&gt;</code> 标签的类型定义。我们可以看到，它继承了更加通用的 <code>HTMLElement</code> 类型，并且扩展了一个即将被废弃的 <code>align</code> 属性，以及两组 <code>addEventListener</code> 和 <code>removeEventListener</code>，注意这里使用了重载。</li>
</ul>
<p><img src="https://poetries1.gitee.io/img-repo/20190903/3.png" alt></p>
<blockquote>
<p>这里的命名也不是随便起的，都是在 MDN 上可以查到的。还是以 <code>&lt;div&gt;</code> 为例，我们已经知道它继承自 <code>HTMLElement</code>，其实再往上，<code>HTMLElement</code> 继承自 <code>Element</code>，<code>Element</code> 又继承自 <code>Node</code>，顺着这条路，你可以挖掘出所有 <code>HTML</code> 标签的类型</p>
</blockquote>
<p><img src="https://poetries1.gitee.io/img-repo/20190903/4.png" alt></p>
<blockquote>
<p>对于一些 DOM 相关的属性，比如 <code>onclick</code>、<code>onchange</code> 等，你都可以如法炮制，找到它们的定义。</p>
</blockquote>
<h3 id="16-7-常见-Types-之-React"><a href="#16-7-常见-Types-之-React" class="headerlink" title="16.7 常见 Types 之 React"></a>16.7 常见 Types 之 React</h3><ul>
<li>关于 TypeScript 的问题，有不少其实是在使用第三方库的时候遇到的，React 就是其中比较典型的一个</li>
<li>其实方法都一样，只不过相关的类型定义不在 <code>TypeScript</code> 中，而是在 <code>@types/react</code> 中。</li>
<li><code>React</code> 的类型定义的名称其实也很直观，比如我们常见的 <code>React.Component</code>，在定义 <code>Class</code> 组件时，我们需要对 <code>Props</code> 和 <code>State</code> 预先进行类型定义，为什么呢？答案就在它的类型定义中</li>
</ul>
<p><img src="https://poetries1.gitee.io/img-repo/20190903/5.png" alt></p>
<ul>
<li>再比如，当我们在写一些组件时，我们可能会需要向下传递 <code>this.props.children</code>，但 <code>children</code> 并没有被设为默认值，需要我们自己定义到 <code>props</code> 上，那么它的类型应该是什么呢</li>
<li>到类型定义中搜一下关键字 <code>children</code>，很快我们就找到了下面的定义</li>
</ul>
<p><img src="https://poetries1.gitee.io/img-repo/20190903/6.png" alt></p>
<blockquote>
<p>所有 <code>React</code> 中 <code>JSX</code> 所代表的内容，无论是 <code>render()</code> 的返回，还是 <code>children</code>，我们都可以定义为一个 <code>ReactNode</code>。那这个 <code>ReactNode</code> 长什么样呢？我们通过右键继续寻找</p>
</blockquote>
<p><img src="https://poetries1.gitee.io/img-repo/20190903/7.png" alt></p>
<blockquote>
<p>看到这里，我们不光找到了我们想要的类型，还顺带明白了为什么 <code>render()</code> 可以返回 <code>boolean</code>、<code>null</code>、<code>undefined</code> 表示不渲染任何内容。<br>那么事件呢？当我们给组件定义事件处理函数的时候，也经常会被要求指定类型。还是老办法，找不到咱就搜，比如 <code>onClick</code> 不清楚，那我们就以它为关键字去搜</p>
</blockquote>
<p><img src="https://poetries1.gitee.io/img-repo/20190903/8.png" alt></p>
<blockquote>
<p>据此我们找到一个叫 <code>MouseEventHandler</code> 的定义，这名字，够直白吧。好了，我们找到想要的了。不过既然来了，不如继续看一下，看看还能发现什么。我们右键 <code>MouseEventHandler</code> 急需往下看：</p>
</blockquote>
<p><img src="https://poetries1.gitee.io/img-repo/20190903/9.png" alt></p>
<blockquote>
<p>看到了吗，所有的事件处理函数都有对应的定义，每个都需要一个泛型参数，传递了事件的类型，名称也挺直白的</p>
</blockquote>
<p><img src="https://poetries1.gitee.io/img-repo/20190903/10.png" alt></p>
<blockquote>
<p>事件的类型也被我们挖出来了，以后如果需要单独定义一个事件相关的类型，就可以直接用了。以此类推，不管是什么东西的类型，都可以去它们对应的 <code>@types/xxx</code>里，按关键字搜</p>
</blockquote>
<h3 id="16-8-多重-extends"><a href="#16-8-多重-extends" class="headerlink" title="16.8 多重 extends"></a>16.8 多重 extends</h3><ul>
<li>我们知道 <code>Interface</code> 是可以多继承的，<code>extends</code> 后面可以跟多个其它 <code>Interface</code>，我们不能保证被继承的多个 <code>Interface</code> 一定没有重复的属性，那么当属性重复，但类型定义不同时，最终的结果会怎么样呢？</li>
<li>在 <code>TypeScript</code> 中，<code>Interface</code> 会按照从右往左的顺序去合并多个被继承的 <code>Interface</code>，也就是说，同名属性，左边的会覆盖右边的</li>
</ul>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line">interface A &#123;</span><br><span class="line">  value?: string</span><br><span class="line">&#125;</span><br><span class="line">interface B &#123;</span><br><span class="line">  value: string</span><br><span class="line">&#125;</span><br><span class="line">interface C &#123;</span><br><span class="line">  value: number</span><br><span class="line">&#125;</span><br><span class="line">interface D extends A, B &#123;&#125;<span class="comment">// value?: string</span></span><br><span class="line">interface E extends B, C &#123;&#125;<span class="comment">// value: string</span></span><br></pre></td></tr></table></figure>
<h3 id="16-9-obj-prop-无法访问怎么办"><a href="#16-9-obj-prop-无法访问怎么办" class="headerlink" title="16.9 obj[prop] 无法访问怎么办"></a>16.9 obj[prop] 无法访问怎么办</h3><ul>
<li>有时候我们会定义一些集合型的数据，例如对象、枚举等，但在调用的时候，我们未必会直接通过 <code>obj.prop</code> 的形式去调用，可能会是以 <code>obj[prop]</code> 这种动态索引的形式去访问，但通过动态索引的方式就无法确定最终访问的元素是否存在，因此在 <code>TypeScript</code> 中，默认是不允许这种操作的</li>
<li>但这又是个非常合理，而且非常常见的场景，怎么办呢？<code>TypeScript</code> 允许为类型添加索引，以实现这一点。</li>
</ul>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line">interface Foo &#123;</span><br><span class="line">  x: string,</span><br><span class="line">  y: number</span><br><span class="line">  [index: string]: string | number</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<ul>
<li>这个方法虽然有效，但每次都要手动为类型加索引，重复多了也挺心累的。包括在一些「配置对象」中，我们甚至无法确定有哪些类型，有没有一种更加通用、更加一劳永逸的方法。</li>
<li>其实在 <code>TypeScript</code>的官方文档中就有提到这个方案，官方管它叫 <code>OptionBag</code>，大概就是指 <code>config</code>、o<code>ption</code> 等用于提供配置信息的这么一类参数。我不是很确定这到底是个常规的英文单词，还是 <code>TypeScript</code> 中特定的术语（个人感觉是前者），反正就这么个意思吧。<br>简单说来，我们可以定义下面这样一个类型：</li>
</ul>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line">interface OptionBag &#123;</span><br><span class="line">  [index: string]: any</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<ul>
<li>这是一个非常通用的结构，以字符串为键，值可以是任何类型，并且支持索引 —— 这不就是 <code>Object</code> 么。</li>
<li>之后所有需要动态索引的结构，或是作为配置对象的结构，都可以直接指定为，或是继承 <code>OptionBag</code>。这个方案以牺牲一定的类型检查为代价，换取了操作上的便利。</li>
<li>理论上讲，<code>OptionBag</code> 可以适用于所有类似对象这样的结构，但不建议各位真就这么做。这个方案只能是用在一些对类型要求不那么严格，或是无法预知类型的场景中，能够确定的类型还是尽可能地写一下，否则就失去了使用 <code>TypeScript</code> 意义了</li>
</ul>
<h2 id="十七、其他技巧"><a href="#十七、其他技巧" class="headerlink" title="十七、其他技巧"></a>十七、其他技巧</h2><p><strong>1. 安全导航操作符 ( ?. )和非空断言操作符（!.）</strong></p>
<ul>
<li><strong>安全导航操作符 ( ?. ) 和空属性路径</strong>： </li>
</ul>
<blockquote>
<p>为了解决导航时变量值为null时，页面运行时出错的问题</p>
</blockquote>
<ul>
<li><strong>非空断言操作符</strong></li>
</ul>
<blockquote>
<p>能确定变量值一定不为空时使用。与安全导航操作符不同的是，非空断言操作符不会防止出现 <code>null</code> 或 <code>undefined</code></p>
</blockquote>
<figure class="highlight plain"><table><tr><td class="code"><pre><span class="line">let s = e!.name; // 断言e是非空并访问name属性</span><br></pre></td></tr></table></figure>
<h1 id="第二章-工程篇"><a href="#第二章-工程篇" class="headerlink" title="第二章 工程篇"></a>第二章 工程篇</h1><p><img src="https://poetries1.gitee.io/img-repo/20190903/gongcheng-1.webp" alt><br><img src="https://poetries1.gitee.io/img-repo/20190903/gongcheng-2.webp" alt><br><img src="https://poetries1.gitee.io/img-repo/20190903/gongcheng-3.webp" alt><br><img src="https://poetries1.gitee.io/img-repo/20190903/gongcheng-4.webp" alt><br><img src="https://poetries1.gitee.io/img-repo/20190903/gongcheng-5.webp" alt><br><img src="https://poetries1.gitee.io/img-repo/20190903/gongcheng-6.webp" alt><br><img src="https://poetries1.gitee.io/img-repo/20190903/gongcheng-7.webp" alt><br><img src="https://poetries1.gitee.io/img-repo/20190903/gongcheng-8.webp" alt></p>
<h2 id="一、使用命名空间"><a href="#一、使用命名空间" class="headerlink" title="一、使用命名空间"></a>一、使用命名空间</h2><blockquote>
<p>不要在一个模块中使用命名空间，最好在一个全局中使用</p>
</blockquote>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line"><span class="comment">// a.ts</span></span><br><span class="line">namespace Shape &#123;</span><br><span class="line">    <span class="keyword">const</span> pi = <span class="built_in">Math</span>.PI</span><br><span class="line">    <span class="keyword">export</span> <span class="function"><span class="keyword">function</span> <span class="title">cricle</span>(<span class="params">r: number</span>) </span>&#123;</span><br><span class="line">        <span class="keyword">return</span> pi * r ** <span class="number">2</span></span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line"><span class="comment">// b.ts</span></span><br><span class="line"></span><br><span class="line"><span class="comment">// 三斜线引用a</span></span><br><span class="line"><span class="comment">/// &lt;reference path="a.ts" /&gt;</span></span><br><span class="line">namespace Shape &#123;</span><br><span class="line">    <span class="keyword">export</span> <span class="function"><span class="keyword">function</span> <span class="title">square</span>(<span class="params">x: number</span>) </span>&#123;</span><br><span class="line">        <span class="keyword">return</span> x * x</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="built_in">console</span>.log(Shape.cricle(<span class="number">2</span>))</span><br><span class="line"><span class="built_in">console</span>.log(Shape.square(<span class="number">2</span>))</span><br><span class="line"></span><br><span class="line"><span class="comment">// 更方便使用 不是es6中的import</span></span><br><span class="line"><span class="keyword">import</span> cricle = Shape.cricle</span><br><span class="line"><span class="built_in">console</span>.log(cricle(<span class="number">2</span>))</span><br></pre></td></tr></table></figure>
<h2 id="二、理解联合声明"><a href="#二、理解联合声明" class="headerlink" title="二、理解联合声明"></a>二、理解联合声明</h2><figure class="highlight js"><table><tr><td class="code"><pre><span class="line"><span class="comment">// 接口声明合并</span></span><br><span class="line">interface A &#123;</span><br><span class="line">    x: number;</span><br><span class="line">    <span class="comment">// y: string;</span></span><br><span class="line">    foo(bar: number): number; <span class="comment">// 5</span></span><br><span class="line">    foo(bar: <span class="string">'a'</span>): string; <span class="comment">// 2</span></span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">interface A &#123;</span><br><span class="line">    y: number;</span><br><span class="line">    foo(bar: string): string; <span class="comment">// 3</span></span><br><span class="line">    foo(bar: string[]): string[]; <span class="comment">// 4</span></span><br><span class="line">    foo(bar: <span class="string">'b'</span>): string; <span class="comment">// 1</span></span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">let</span> a: A = &#123;</span><br><span class="line">    x: <span class="number">1</span>,</span><br><span class="line">    y: <span class="number">2</span>,</span><br><span class="line">    foo(bar: any) &#123;</span><br><span class="line">        <span class="keyword">return</span> bar</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">// 命名空间和类声明合并--命名空间需要放到后面</span></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">C</span> </span>&#123;&#125;</span><br><span class="line">namespace C &#123;</span><br><span class="line">    <span class="keyword">export</span> <span class="keyword">let</span> state = <span class="number">1</span></span><br><span class="line">&#125;</span><br><span class="line"><span class="built_in">console</span>.log(C.state)</span><br><span class="line"></span><br><span class="line"><span class="comment">// 命名空间和函数声明合并--命名空间需要放到后面</span></span><br><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">Lib</span>(<span class="params"></span>) </span>&#123;&#125;</span><br><span class="line">namespace Lib &#123;</span><br><span class="line">    <span class="keyword">export</span> <span class="keyword">let</span> version = <span class="string">'1.0'</span></span><br><span class="line">&#125;</span><br><span class="line"><span class="built_in">console</span>.log(Lib.version)</span><br><span class="line"></span><br><span class="line"><span class="comment">// 命名空间和枚举声明合并--位置没有要求</span></span><br><span class="line">enum Color &#123;</span><br><span class="line">    Red,</span><br><span class="line">    Yellow,</span><br><span class="line">    Blue</span><br><span class="line">&#125;</span><br><span class="line">namespace Color &#123;</span><br><span class="line">    <span class="keyword">export</span> <span class="function"><span class="keyword">function</span> <span class="title">mix</span>(<span class="params"></span>) </span>&#123;&#125;</span><br><span class="line">&#125;</span><br><span class="line"><span class="built_in">console</span>.log(Color)</span><br></pre></td></tr></table></figure>
<h2 id="三、如何编写声明文件–引入类库"><a href="#三、如何编写声明文件–引入类库" class="headerlink" title="三、如何编写声明文件–引入类库"></a>三、如何编写声明文件–引入类库</h2><blockquote>
<p>类库分为三类：全局类库、模块类库、<code>UMD</code>类库</p>
</blockquote>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line">declare <span class="keyword">var</span> <span class="comment">// 声明全局变量</span></span><br><span class="line">declare <span class="function"><span class="keyword">function</span> // 声明全局方法</span></span><br><span class="line"><span class="function"><span class="title">declare</span> <span class="title">class</span> // 声明全局类</span></span><br><span class="line"><span class="function"><span class="title">declare</span> <span class="title">enum</span> // 声明全局枚举类型</span></span><br><span class="line"><span class="function"><span class="title">declare</span> <span class="title">global</span> // 扩展全局变量</span></span><br><span class="line"><span class="function"><span class="title">declare</span> <span class="title">module</span> // 扩展模块</span></span><br></pre></td></tr></table></figure>
<blockquote>
<p>大多数的声明文件社区已经帮我们安装好了，使用<code>@types/包名</code>声明文件即可</p>
</blockquote>
<blockquote>
<p>Typescript声明文件查找 <a href="https://microsoft.github.io/TypeSearch/" target="_blank" rel="noopener">https://microsoft.github.io/TypeSearch/</a></p>
</blockquote>
<p><strong>以jquery为例子</strong></p>
<figure class="highlight plain"><table><tr><td class="code"><pre><span class="line">yarn add @types/jquery</span><br></pre></td></tr></table></figure>
<p><strong>引入了一个JS类库，但是社区又没有提供类型声明文件，我该如何去编写它的类型声明文件</strong></p>
<blockquote>
<p>先确定这个库的类型，全局库、模块库、还是UMD库，然后参照下面介绍的方法，把它的<code>API</code>声明逐步添加进来（暂时用不到的<code>API</code>也可以不写）</p>
</blockquote>
<h3 id="3-1-三种类库声明文件写法"><a href="#3-1-三种类库声明文件写法" class="headerlink" title="3.1 三种类库声明文件写法"></a>3.1 三种类库声明文件写法</h3><h4 id="3-1-1-全局库"><a href="#3-1-1-全局库" class="headerlink" title="3.1.1 全局库"></a>3.1.1 全局库</h4><figure class="highlight js"><table><tr><td class="code"><pre><span class="line"><span class="comment">// global-lib.d.ts</span></span><br><span class="line">    </span><br><span class="line">declare <span class="function"><span class="keyword">function</span> <span class="title">globalLib</span>(<span class="params">options: globalLib.Options</span>): <span class="title">void</span>;</span></span><br><span class="line"><span class="function">// 函数和命名空间的声明合并 为这个函数提供了一些属性</span></span><br><span class="line"><span class="function"><span class="title">declare</span> <span class="title">namespace</span> <span class="title">globalLib</span> </span>&#123;</span><br><span class="line">    <span class="keyword">const</span> version: string;</span><br><span class="line">    <span class="function"><span class="keyword">function</span> <span class="title">doSomething</span>(<span class="params"></span>): <span class="title">void</span>;</span></span><br><span class="line"><span class="function">    <span class="title">interface</span> <span class="title">Options</span> </span>&#123;</span><br><span class="line">        [key: string]: any</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line"><span class="comment">// global-lib.js</span></span><br><span class="line"><span class="comment">// 和声明文件对应</span></span><br><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">globalLib</span>(<span class="params">options</span>) </span>&#123;</span><br><span class="line">    <span class="built_in">console</span>.log(options);</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">globalLib.version = <span class="string">'1.0.0'</span>;</span><br><span class="line"></span><br><span class="line">globalLib.doSomething = <span class="function"><span class="keyword">function</span>(<span class="params"></span>) </span>&#123;</span><br><span class="line">    <span class="built_in">console</span>.log(<span class="string">'globalLib do something'</span>);</span><br><span class="line">&#125;;</span><br></pre></td></tr></table></figure>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line"><span class="comment">// 全局使用 index.ts</span></span><br><span class="line">globalLib(&#123;<span class="attr">x</span>:<span class="number">1</span>&#125;)</span><br><span class="line">globalLib.doSomething()</span><br></pre></td></tr></table></figure>
<h4 id="3-1-2-模块类库"><a href="#3-1-2-模块类库" class="headerlink" title="3.1.2 模块类库"></a>3.1.2 模块类库</h4><figure class="highlight js"><table><tr><td class="code"><pre><span class="line"><span class="comment">// module-lib.d.ts</span></span><br><span class="line">declare <span class="function"><span class="keyword">function</span> <span class="title">moduleLib</span>(<span class="params">options: Options</span>): <span class="title">void</span></span></span><br><span class="line"><span class="function"></span></span><br><span class="line"><span class="function"><span class="title">interface</span> <span class="title">Options</span> </span>&#123;</span><br><span class="line">    [key: string]: any</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">declare namespace moduleLib &#123;</span><br><span class="line">    <span class="keyword">const</span> version: string</span><br><span class="line">    <span class="function"><span class="keyword">function</span> <span class="title">doSomething</span>(<span class="params"></span>): <span class="title">void</span></span></span><br><span class="line"><span class="function">&#125;</span></span><br><span class="line"><span class="function"></span></span><br><span class="line"><span class="function"><span class="title">export</span> = <span class="title">moduleLib</span></span></span><br></pre></td></tr></table></figure>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line"><span class="comment">// module-lib.js</span></span><br><span class="line"><span class="keyword">const</span> version = <span class="string">'1.0.0'</span>;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">doSomething</span>(<span class="params"></span>) </span>&#123;</span><br><span class="line">    <span class="built_in">console</span>.log(<span class="string">'moduleLib do something'</span>);</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">moduleLib</span>(<span class="params">options</span>) </span>&#123;</span><br><span class="line">    <span class="built_in">console</span>.log(options);</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">moduleLib.version = version;</span><br><span class="line">moduleLib.doSomething = doSomething;</span><br><span class="line"></span><br><span class="line"><span class="built_in">module</span>.exports = moduleLib;</span><br></pre></td></tr></table></figure>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line"><span class="comment">// index.ts 使用</span></span><br><span class="line"><span class="keyword">import</span> umdLib <span class="keyword">from</span> <span class="string">'./umd-lib'</span></span><br><span class="line"></span><br><span class="line">umdLib.doSomething()</span><br></pre></td></tr></table></figure>
<h4 id="3-1-3-UMD类库"><a href="#3-1-3-UMD类库" class="headerlink" title="3.1.3 UMD类库"></a>3.1.3 UMD类库</h4><figure class="highlight js"><table><tr><td class="code"><pre><span class="line"><span class="comment">// umd-lib.d.ts</span></span><br><span class="line"></span><br><span class="line">declare namespace umdLib &#123;</span><br><span class="line">    <span class="comment">// 省略了export</span></span><br><span class="line">    <span class="keyword">const</span> version: string</span><br><span class="line">    <span class="function"><span class="keyword">function</span> <span class="title">doSomething</span>(<span class="params"></span>): <span class="title">void</span></span></span><br><span class="line"><span class="function">&#125;</span></span><br><span class="line"><span class="function"></span></span><br><span class="line"><span class="function">// <span class="title">UMD</span>库不可缺少的语句</span></span><br><span class="line"><span class="function"><span class="title">export</span> <span class="title">as</span> <span class="title">namespace</span> <span class="title">umdLib</span></span></span><br><span class="line"><span class="function"></span></span><br><span class="line"><span class="function"><span class="title">export</span> = <span class="title">umdLib</span></span></span><br></pre></td></tr></table></figure>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line"><span class="comment">// umd-lib.js</span></span><br><span class="line">(<span class="function"><span class="keyword">function</span> (<span class="params">root, factory</span>) </span>&#123;</span><br><span class="line">    <span class="keyword">if</span> (<span class="keyword">typeof</span> define === <span class="string">"function"</span> &amp;&amp; define.amd) &#123;</span><br><span class="line">        define(factory);</span><br><span class="line">    &#125; <span class="keyword">else</span> <span class="keyword">if</span> (<span class="keyword">typeof</span> <span class="built_in">module</span> === <span class="string">"object"</span> &amp;&amp; <span class="built_in">module</span>.exports) &#123;</span><br><span class="line">        <span class="built_in">module</span>.exports = factory();</span><br><span class="line">    &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">        root.umdLib = factory();</span><br><span class="line">    &#125;</span><br><span class="line">&#125;(<span class="keyword">this</span>, <span class="function"><span class="keyword">function</span>(<span class="params"></span>) </span>&#123;</span><br><span class="line">    <span class="keyword">return</span> &#123;</span><br><span class="line">        <span class="comment">// 需要为这两个成员编写声明文件</span></span><br><span class="line">        version: <span class="string">'1.0.0'</span>,</span><br><span class="line">        doSomething() &#123;</span><br><span class="line">            <span class="built_in">console</span>.log(<span class="string">'umdLib do something'</span>);</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;))</span><br></pre></td></tr></table></figure>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line"><span class="comment">// index.ts使用</span></span><br><span class="line"><span class="keyword">import</span> umdLib <span class="keyword">from</span> <span class="string">'./umd-lib'</span></span><br><span class="line"><span class="comment">// 可以不用导入umd-lib模块。但是需要打开tsconfig.tson中的umd配置</span></span><br><span class="line">umdLib.doSomething()</span><br></pre></td></tr></table></figure>
<h3 id="3-2-两种插件声明文件写法"><a href="#3-2-两种插件声明文件写法" class="headerlink" title="3.2 两种插件声明文件写法"></a>3.2 两种插件声明文件写法</h3><h4 id="3-2-1-模块化插件declare-module"><a href="#3-2-1-模块化插件declare-module" class="headerlink" title="3.2.1 模块化插件declare module"></a>3.2.1 模块化插件declare module</h4><blockquote>
<p><code>declare module</code> 可以给类库添加一些自定义方法。 扩展模块</p>
</blockquote>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line"><span class="comment">// 模块插件</span></span><br><span class="line"><span class="keyword">import</span> m <span class="keyword">from</span> <span class="string">'moment'</span>;</span><br><span class="line">declare <span class="built_in">module</span> <span class="string">'moment'</span> &#123;</span><br><span class="line">    <span class="comment">// 给moment自定义一些方法</span></span><br><span class="line">    <span class="keyword">export</span> <span class="function"><span class="keyword">function</span> <span class="title">myFunction</span>(<span class="params"></span>): <span class="title">void</span>;</span></span><br><span class="line"><span class="function">&#125;</span></span><br><span class="line"><span class="function"><span class="title">m</span>.<span class="title">myFunction</span> = (<span class="params"></span>) =&gt; </span>&#123;&#125;</span><br></pre></td></tr></table></figure>
<h4 id="3-2-2-全局插件declare-global"><a href="#3-2-2-全局插件declare-global" class="headerlink" title="3.2.2 全局插件declare global"></a>3.2.2 全局插件declare global</h4><figure class="highlight js"><table><tr><td class="code"><pre><span class="line"><span class="comment">// 全局插件</span></span><br><span class="line">declare global &#123;</span><br><span class="line">    namespace globalLib &#123;</span><br><span class="line">        <span class="function"><span class="keyword">function</span> <span class="title">doAnyting</span>(<span class="params"></span>): <span class="title">void</span></span></span><br><span class="line"><span class="function">    &#125;</span></span><br><span class="line"><span class="function">&#125;</span></span><br><span class="line"><span class="function">// 在全局变量添加方法</span></span><br><span class="line"><span class="function">// 会对全局变量造成污染 一般不这么做</span></span><br><span class="line"><span class="function"><span class="title">globalLib</span>.<span class="title">doAnyting</span> = (<span class="params"></span>) =&gt; </span>&#123;&#125;</span><br></pre></td></tr></table></figure>
<h3 id="3-3-jquery声明文件示例"><a href="#3-3-jquery声明文件示例" class="headerlink" title="3.3 jquery声明文件示例"></a>3.3 jquery声明文件示例</h3><figure class="highlight js"><table><tr><td class="code"><pre><span class="line"><span class="comment">// index.d.ts入口</span></span><br><span class="line"></span><br><span class="line"><span class="comment">// Type definitions for jquery 3.3</span></span><br><span class="line"><span class="comment">// Project: https://jquery.com</span></span><br><span class="line"><span class="comment">// Definitions by: Leonard Thieu &lt;https://github.com/leonard-thieu&gt;</span></span><br><span class="line"><span class="comment">//                 Boris Yankov &lt;https://github.com/borisyankov&gt;</span></span><br><span class="line"><span class="comment">//                 Christian Hoffmeister &lt;https://github.com/choffmeister&gt;</span></span><br><span class="line"><span class="comment">//                 Steve Fenton &lt;https://github.com/Steve-Fenton&gt;</span></span><br><span class="line"><span class="comment">//                 Diullei Gomes &lt;https://github.com/Diullei&gt;</span></span><br><span class="line"><span class="comment">//                 Tass Iliopoulos &lt;https://github.com/tasoili&gt;</span></span><br><span class="line"><span class="comment">//                 Jason Swearingen &lt;https://github.com/jasons-novaleaf&gt;</span></span><br><span class="line"><span class="comment">//                 Sean Hill &lt;https://github.com/seanski&gt;</span></span><br><span class="line"><span class="comment">//                 Guus Goossens &lt;https://github.com/Guuz&gt;</span></span><br><span class="line"><span class="comment">//                 Kelly Summerlin &lt;https://github.com/ksummerlin&gt;</span></span><br><span class="line"><span class="comment">//                 Basarat Ali Syed &lt;https://github.com/basarat&gt;</span></span><br><span class="line"><span class="comment">//                 Nicholas Wolverson &lt;https://github.com/nwolverson&gt;</span></span><br><span class="line"><span class="comment">//                 Derek Cicerone &lt;https://github.com/derekcicerone&gt;</span></span><br><span class="line"><span class="comment">//                 Andrew Gaspar &lt;https://github.com/AndrewGaspar&gt;</span></span><br><span class="line"><span class="comment">//                 Seikichi Kondo &lt;https://github.com/seikichi&gt;</span></span><br><span class="line"><span class="comment">//                 Benjamin Jackman &lt;https://github.com/benjaminjackman&gt;</span></span><br><span class="line"><span class="comment">//                 Poul Sorensen &lt;https://github.com/s093294&gt;</span></span><br><span class="line"><span class="comment">//                 Josh Strobl &lt;https://github.com/JoshStrobl&gt;</span></span><br><span class="line"><span class="comment">//                 John Reilly &lt;https://github.com/johnnyreilly&gt;</span></span><br><span class="line"><span class="comment">//                 Dick van den Brink &lt;https://github.com/DickvdBrink&gt;</span></span><br><span class="line"><span class="comment">//                 Thomas Schulz &lt;https://github.com/King2500&gt;</span></span><br><span class="line"><span class="comment">//                 Terry Mun &lt;https://github.com/terrymun&gt;</span></span><br><span class="line"><span class="comment">// Definitions: https://github.com/DefinitelyTyped/DefinitelyTyped</span></span><br><span class="line"><span class="comment">// TypeScript Version: 2.3</span></span><br><span class="line"></span><br><span class="line"><span class="comment">// 三斜线引入模块</span></span><br><span class="line"></span><br><span class="line"><span class="comment">/// &lt;reference types="sizzle" /&gt;</span></span><br><span class="line"><span class="comment">/// &lt;reference path="JQueryStatic.d.ts" /&gt;</span></span><br><span class="line"><span class="comment">/// &lt;reference path="JQuery.d.ts" /&gt;</span></span><br><span class="line"><span class="comment">/// &lt;reference path="misc.d.ts" /&gt;</span></span><br><span class="line"><span class="comment">/// &lt;reference path="legacy.d.ts" /&gt;</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">export</span> = jQuery;</span><br></pre></td></tr></table></figure>
<h2 id="四、配置tsconfig-json"><a href="#四、配置tsconfig-json" class="headerlink" title="四、配置tsconfig.json"></a>四、配置tsconfig.json</h2><h3 id="4-1-基础配置"><a href="#4-1-基础配置" class="headerlink" title="4.1 基础配置"></a>4.1 基础配置</h3><figure class="highlight js"><table><tr><td class="code"><pre><span class="line">&#123;</span><br><span class="line">  <span class="comment">// ===与文件相关的选项===</span></span><br><span class="line">  <span class="string">"files"</span> : [<span class="string">'src/index.ts'</span>], <span class="comment">// 编译的文件列表</span></span><br><span class="line">  <span class="string">"include"</span>: [<span class="string">'src'</span>], <span class="comment">// 指定编译文件</span></span><br><span class="line">  <span class="string">"exclude"</span>: [<span class="string">'src/lib'</span>], <span class="comment">// 排除编译文件</span></span><br><span class="line">  </span><br><span class="line">  <span class="comment">// ====与编译相关的选项====</span></span><br><span class="line">  <span class="string">"compilerOptions"</span>: &#123;</span><br><span class="line">      <span class="comment">// "incremental": true,                // 增量编译，再次编译会增量编译</span></span><br><span class="line">      <span class="comment">// "tsBuildInfoFile": "./buildFile",   // 增量编译文件的存储位置</span></span><br><span class="line">      <span class="comment">// "diagnostics": true,                // 打印诊断信息</span></span><br><span class="line"></span><br><span class="line">      <span class="comment">// "target": "es5",           // 目标语言的版本</span></span><br><span class="line">      <span class="comment">// "module": "commonjs",      // 生成代码的模块标准</span></span><br><span class="line">      <span class="comment">// "outFile": "./app.js",     // 将多个相互依赖的文件生成一个文件，可以用在 AMD 模块中</span></span><br><span class="line">        </span><br><span class="line">       <span class="comment">// 比如你需要使用es2019方法 需要在这里导入模块 "lib": ['es2019.arrary']</span></span><br><span class="line">      <span class="comment">// "lib": [],                 // TS 需要引用的库，即声明文件，es5 默认 "dom", "es5", "scripthost"</span></span><br><span class="line"></span><br><span class="line">      <span class="comment">// "allowJs": true,           // 允许编译 JS 文件（js、jsx）</span></span><br><span class="line">      <span class="comment">// "checkJs": true,           // 允许在 JS 文件中报错，通常与 allowJS 一起使用</span></span><br><span class="line">      <span class="comment">// "outDir": "./out",         // 指定输出目录</span></span><br><span class="line">      <span class="comment">// "rootDir": "./",           // 指定输入文件目录（用于输出）</span></span><br><span class="line"></span><br><span class="line">      <span class="comment">// "declaration": true,         // 生成声明文件</span></span><br><span class="line">      <span class="comment">// "declarationDir": "./d",     // 声明文件的路径</span></span><br><span class="line">      <span class="comment">// "emitDeclarationOnly": true, // 只生成声明文件</span></span><br><span class="line">      <span class="comment">// "sourceMap": true,           // 生成目标文件的 sourceMap</span></span><br><span class="line">      <span class="comment">// "inlineSourceMap": true,     // 生成目标文件的 inline sourceMap</span></span><br><span class="line">      <span class="comment">// "declarationMap": true,      // 生成声明文件的 sourceMap</span></span><br><span class="line">      <span class="comment">// "typeRoots": [],             // 声明文件目录，默认 node_modules/@types</span></span><br><span class="line">      <span class="comment">// "types": [],                 // 声明文件包</span></span><br><span class="line"></span><br><span class="line">      <span class="comment">// "removeComments": true,    // 删除注释</span></span><br><span class="line"></span><br><span class="line">      <span class="comment">// "noEmit": true,            // 不输出文件</span></span><br><span class="line">      <span class="comment">// "noEmitOnError": true,     // 发生错误时不输出文件</span></span><br><span class="line"></span><br><span class="line">      <span class="comment">// "noEmitHelpers": true,     // 不生成 helper 函数，需额外安装 ts-helpers</span></span><br><span class="line">      <span class="comment">// "importHelpers": true,     // 通过 tslib 引入 helper 函数，文件必须是模块</span></span><br><span class="line"></span><br><span class="line">      <span class="comment">// "downlevelIteration": true,    // 降级遍历器的实现（es3/5）</span></span><br><span class="line"></span><br><span class="line">      <span class="comment">// "strict": true,                        // 开启所有严格的类型检查</span></span><br><span class="line">      <span class="comment">// "alwaysStrict": false,                 // 在代码中注入 "use strict";</span></span><br><span class="line">      <span class="comment">// "noImplicitAny": false,                // 不允许隐式的 any 类型</span></span><br><span class="line">      <span class="comment">// "strictNullChecks": false,             // 不允许把 null、undefined 赋值给其他类型变量</span></span><br><span class="line">      <span class="comment">// "strictFunctionTypes": false           // 不允许函数参数双向协变</span></span><br><span class="line">      <span class="comment">// "strictPropertyInitialization": false, // 类的实例属性必须初始化</span></span><br><span class="line">      <span class="comment">// "strictBindCallApply": false,          // 严格的 bind/call/apply 检查</span></span><br><span class="line">      <span class="comment">// "noImplicitThis": false,               // 不允许 this 有隐式的 any 类型</span></span><br><span class="line"></span><br><span class="line">      <span class="comment">// "noUnusedLocals": true,                // 检查只声明，未使用的局部变量</span></span><br><span class="line">      <span class="comment">// "noUnusedParameters": true,            // 检查未使用的函数参数</span></span><br><span class="line">      <span class="comment">// "noFallthroughCasesInSwitch": true,    // 防止 switch 语句贯穿</span></span><br><span class="line">      <span class="comment">// "noImplicitReturns": true,             // 每个分支都要有返回值</span></span><br><span class="line"></span><br><span class="line">      <span class="comment">// "esModuleInterop": true,               // 允许 export = 导出，由import from 导入</span></span><br><span class="line">      <span class="comment">// "allowUmdGlobalAccess": true,          // 允许在模块中访问 UMD 全局变量</span></span><br><span class="line">      <span class="comment">// "moduleResolution": "node",            // 模块解析策略</span></span><br><span class="line">      <span class="comment">// "baseUrl": "./",                       // 解析非相对模块的基地址</span></span><br><span class="line">      <span class="comment">// "paths": &#123;                             // 路径映射，相对于 baseUrl</span></span><br><span class="line">      <span class="comment">//   "jquery": ["node_modules/jquery/dist/jquery.slim.min.js"]</span></span><br><span class="line">      <span class="comment">// &#125;,</span></span><br><span class="line">      <span class="comment">// "rootDirs": ["src", "out"],            // 将多个目录放在一个虚拟目录下，用于运行时</span></span><br><span class="line"></span><br><span class="line">      <span class="comment">// "listEmittedFiles": true,        // 打印输出的文件</span></span><br><span class="line">      <span class="comment">// "listFiles": true,               // 打印编译的文件（包括引用的声明文件）</span></span><br><span class="line">  &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<blockquote>
<p>也可以把公共的抽离出来</p>
</blockquote>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line"><span class="comment">// tsconfig.base.json</span></span><br><span class="line"></span><br><span class="line">&#123;</span><br><span class="line">  <span class="string">"files"</span> : [<span class="string">'src/index.ts'</span>], <span class="comment">// 编译的文件列表</span></span><br><span class="line">  <span class="string">"include"</span>: [<span class="string">'src'</span>], <span class="comment">// 指定编译文件</span></span><br><span class="line">  <span class="string">"exclude"</span>: [<span class="string">'src/lib'</span>], <span class="comment">// 排除编译文件</span></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line"><span class="string">"extends"</span>: <span class="string">'./tsconfig.base'</span>,</span><br><span class="line"><span class="string">"exclude"</span>: [] <span class="comment">// 覆盖之前的</span></span><br></pre></td></tr></table></figure>
<h3 id="4-2-工程引用配置多个项目"><a href="#4-2-工程引用配置多个项目" class="headerlink" title="4.2 工程引用配置多个项目"></a>4.2 工程引用配置多个项目</h3><blockquote>
<p>每个项目都有一份独立的<code>tsconfig.json</code>，继承一份公共的配置，最后可单独构建每个子项目工程</p>
</blockquote>
<blockquote>
<p>参考学习<code>typescript</code>项目 <a href="https://github.com/microsoft/TypeScript/tree/master/src" target="_blank" rel="noopener">https://github.com/microsoft/TypeScript/tree/master/src</a></p>
</blockquote>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line"><span class="comment">// 示例 项目入口</span></span><br><span class="line">&#123;</span><br><span class="line">  <span class="string">"compilerOptions"</span>: &#123;</span><br><span class="line">    <span class="string">"target"</span>: <span class="string">"es5"</span>,</span><br><span class="line">    <span class="string">"module"</span>: <span class="string">"commonjs"</span>,</span><br><span class="line">    <span class="string">"strict"</span>: <span class="literal">true</span>,</span><br><span class="line">    <span class="string">"composite"</span>: <span class="literal">true</span>,</span><br><span class="line">    <span class="string">"declaration"</span>: <span class="literal">true</span></span><br><span class="line">  &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line"><span class="comment">// 子工程1</span></span><br><span class="line"><span class="comment">// src/client/tsconfig.json</span></span><br><span class="line">&#123;</span><br><span class="line">    <span class="string">"extends"</span>: <span class="string">"../../tsconfig.json"</span>, <span class="comment">//继承基础配置</span></span><br><span class="line">    <span class="string">"compilerOptions"</span>: &#123;</span><br><span class="line">        <span class="string">"outDir"</span>: <span class="string">"../../dist/client"</span>, <span class="comment">// 输出文件</span></span><br><span class="line">    &#125;,</span><br><span class="line">    <span class="string">"references"</span>: [</span><br><span class="line">        &#123; <span class="string">"path"</span>: <span class="string">"../common"</span> &#125; <span class="comment">// 依赖文件</span></span><br><span class="line">    ]</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line"><span class="comment">// 子工程2</span></span><br><span class="line"><span class="comment">// src/server/tsconfig.json</span></span><br><span class="line"></span><br><span class="line">&#123;</span><br><span class="line">    <span class="string">"extends"</span>: <span class="string">"../../tsconfig.json"</span>,</span><br><span class="line">    <span class="string">"compilerOptions"</span>: &#123;</span><br><span class="line">        <span class="string">"outDir"</span>: <span class="string">"../../dist/server"</span>,</span><br><span class="line">    &#125;,</span><br><span class="line">    <span class="string">"references"</span>: [</span><br><span class="line">        &#123; <span class="string">"path"</span>: <span class="string">"../common"</span> &#125;</span><br><span class="line">    ]</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<h2 id="五、编译工具ts-loader、ts-lint"><a href="#五、编译工具ts-loader、ts-lint" class="headerlink" title="五、编译工具ts-loader、ts-lint"></a>五、编译工具ts-loader、ts-lint</h2><p><strong>如何选择Typescript编译器</strong></p>
<blockquote>
<ul>
<li>如果没有使用过<code>babel</code>，首选<code>Typescript</code>自身编译器(可配合<code>Ts-loader</code>使用)</li>
<li>如果项目中已经使用<code>babel</code>，安装<code>@babel/preset-typescript</code>(可配合tsc做类型检查)</li>
<li>两种编译工具不要混用</li>
</ul>
</blockquote>
<p><strong>typescript-eslint与babel-eslint区别</strong></p>
<blockquote>
<ul>
<li><code>babel-eslint</code>支持<code>typescript</code>没有额外的语法检查，抛弃<code>typescript</code>,不支持类型检查</li>
<li><code>typescript-eslint</code>基础typescript的AST,基于创建基于类型信息的规则（<code>tsconfig.json</code>）</li>
</ul>
</blockquote>
<ul>
<li>两者底层机制不一样，不要一起使用</li>
<li><code>babel</code>体系建议使用<code>babel-eslint</code>，否则使用<code>typescript-eslint</code></li>
</ul>
<p><strong>总结</strong></p>
<ul>
<li><p>编译工具</p>
<ul>
<li><code>ts-loader</code></li>
<li><code>@babel/preset-typescript</code></li>
</ul>
</li>
<li><p>代码检查工具</p>
<ul>
<li><code>babel-eslint</code></li>
<li><code>typescript-eslint</code></li>
</ul>
</li>
</ul>
<h2 id="六、使用jest进行单元测试"><a href="#六、使用jest进行单元测试" class="headerlink" title="六、使用jest进行单元测试"></a>六、使用jest进行单元测试</h2><ul>
<li>单元测试工具<ul>
<li><code>ts-jest</code> – 能够在测试用例中进行类型检查</li>
<li><code>babel-jest</code> – 没有进行类型检查</li>
</ul>
</li>
</ul>
<blockquote>
<p>生成配置文件 <code>ts-jest config:init</code></p>
</blockquote>
<h1 id="第三章-项目实战"><a href="#第三章-项目实战" class="headerlink" title="第三章 项目实战"></a>第三章 项目实战</h1><h2 id="一、思维导图"><a href="#一、思维导图" class="headerlink" title="一、思维导图"></a>一、思维导图</h2><p><img src="https://poetries1.gitee.io/img-repo/20190903/1.png" alt><br><img src="https://poetries1.gitee.io/img-repo/20190903/2.png" alt></p>
<h2 id="二、React项目实践"><a href="#二、React项目实践" class="headerlink" title="二、React项目实践"></a>二、React项目实践</h2><h3 id="2-1-手动创建react项目"><a href="#2-1-手动创建react项目" class="headerlink" title="2.1 手动创建react项目"></a>2.1 手动创建react项目</h3><blockquote>
<p>项目代码 <a href="https://github.com/poetries/typescript-in-action/tree/master/ts-react" target="_blank" rel="noopener">https://github.com/poetries/typescript-in-action/tree/master/ts-react</a></p>
</blockquote>
<p><strong>1. 安装依赖文件</strong></p>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line">yarn add @types/react @types/react-dom</span><br></pre></td></tr></table></figure>
<p><strong>2. 修改tsconfig.json</strong>配置</p>
<blockquote>
<p>修改 <code>compilerOptions</code>中的<code>jsx</code>为<code>react</code></p>
</blockquote>
<h3 id="2-2-使用脚手架安装"><a href="#2-2-使用脚手架安装" class="headerlink" title="2.2 使用脚手架安装"></a>2.2 使用脚手架安装</h3><blockquote>
<p>项目代码 <a href="https://github.com/poetries/typescript-in-action/tree/master/ts-react-app" target="_blank" rel="noopener">https://github.com/poetries/typescript-in-action/tree/master/ts-react-app</a></p>
</blockquote>
<figure class="highlight plain"><table><tr><td class="code"><pre><span class="line">create-react-app ts-react-app --typescript</span><br></pre></td></tr></table></figure>
<h4 id="2-2-1-函数组件"><a href="#2-2-1-函数组件" class="headerlink" title="2.2.1 函数组件"></a>2.2.1 函数组件</h4><figure class="highlight js"><table><tr><td class="code"><pre><span class="line"><span class="keyword">import</span> React <span class="keyword">from</span> <span class="string">'react'</span>;</span><br><span class="line"><span class="keyword">import</span> &#123; Button &#125; <span class="keyword">from</span> <span class="string">'antd'</span>;</span><br><span class="line"></span><br><span class="line">interface Greeting &#123;</span><br><span class="line">    name: string;</span><br><span class="line">    firstName: string;</span><br><span class="line">    lastName: string;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">const</span> Hello = <span class="function">(<span class="params">props: Greeting</span>) =&gt;</span> <span class="xml"><span class="tag">&lt;<span class="name">Button</span>&gt;</span>Hello &#123;props.name&#125;<span class="tag">&lt;/<span class="name">Button</span>&gt;</span></span></span><br><span class="line"></span><br><span class="line"><span class="comment">// const Hello: React.FC&lt;Greeting&gt; = (&#123;</span></span><br><span class="line"><span class="comment">//     name,</span></span><br><span class="line"><span class="comment">//     firstName,</span></span><br><span class="line"><span class="comment">//     lastName,</span></span><br><span class="line"><span class="comment">//     children</span></span><br><span class="line"><span class="comment">// &#125;) =&gt; &lt;Button&gt;Hello &#123;name&#125;&lt;/Button&gt;</span></span><br><span class="line"></span><br><span class="line">Hello.defaultProps = &#123;</span><br><span class="line">    firstName: <span class="string">''</span>,</span><br><span class="line">    lastName: <span class="string">''</span></span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">export</span> <span class="keyword">default</span> Hello;</span><br></pre></td></tr></table></figure>
<h4 id="2-2-2-类组件"><a href="#2-2-2-类组件" class="headerlink" title="2.2.2 类组件"></a>2.2.2 类组件</h4><figure class="highlight js"><table><tr><td class="code"><pre><span class="line"><span class="keyword">import</span> React, &#123; Component &#125; <span class="keyword">from</span> <span class="string">'react'</span>;</span><br><span class="line"><span class="keyword">import</span> &#123; Button &#125; <span class="keyword">from</span> <span class="string">'antd'</span>;</span><br><span class="line"></span><br><span class="line">interface Greeting &#123;</span><br><span class="line">    name: string;</span><br><span class="line">    firstName?: string;</span><br><span class="line">    lastName?: string;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">interface HelloState &#123;</span><br><span class="line">    count: number</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">HelloClass</span> <span class="keyword">extends</span> <span class="title">Component</span>&lt;<span class="title">Greeting</span>, <span class="title">HelloState</span>&gt; </span>&#123;</span><br><span class="line">    state: HelloState = &#123;</span><br><span class="line">        count: <span class="number">0</span></span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">static</span> defaultProps = &#123;</span><br><span class="line">        firstName: <span class="string">''</span>,</span><br><span class="line">        lastName: <span class="string">''</span></span><br><span class="line">    &#125;</span><br><span class="line">    render() &#123;</span><br><span class="line">        <span class="keyword">return</span> (</span><br><span class="line">            &lt;&gt;</span><br><span class="line">                &lt;p&gt;你点击了 &#123;<span class="keyword">this</span>.state.count&#125; 次&lt;<span class="regexp">/p&gt;</span></span><br><span class="line"><span class="regexp">                &lt;Button onClick=&#123;() =&gt; &#123;this.setState(&#123;count: this.state.count + 1&#125;)&#125;&#125;&gt;</span></span><br><span class="line"><span class="regexp">                    Hello &#123;this.props.name&#125;</span></span><br><span class="line"><span class="regexp">                &lt;/</span>Button&gt;</span><br><span class="line">            &lt;<span class="regexp">/&gt;</span></span><br><span class="line"><span class="regexp">        )</span></span><br><span class="line"><span class="regexp">    &#125;</span></span><br><span class="line"><span class="regexp">&#125;</span></span><br><span class="line"><span class="regexp"></span></span><br><span class="line"><span class="regexp">export default HelloClass;</span></span><br></pre></td></tr></table></figure>
<h4 id="2-2-3-高阶组件"><a href="#2-2-3-高阶组件" class="headerlink" title="2.2.3 高阶组件"></a>2.2.3 高阶组件</h4><figure class="highlight js"><table><tr><td class="code"><pre><span class="line"><span class="keyword">import</span> React, &#123; Component &#125; <span class="keyword">from</span> <span class="string">'react'</span>;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> HelloClass <span class="keyword">from</span> <span class="string">'./HelloClass'</span>;</span><br><span class="line"></span><br><span class="line">interface Loading &#123;</span><br><span class="line">    loading: boolean</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">HelloHOC</span>&lt;<span class="title">P</span>&gt;(<span class="params">WrappedComponent: React.ComponentType&lt;P&gt;</span>) </span>&#123;</span><br><span class="line">    <span class="keyword">return</span> <span class="class"><span class="keyword">class</span> <span class="keyword">extends</span> <span class="title">Component</span>&lt;<span class="title">P</span> &amp; <span class="title">Loading</span>&gt; </span>&#123;</span><br><span class="line">        render() &#123;</span><br><span class="line">            <span class="keyword">const</span> &#123; loading, ...props &#125; = <span class="keyword">this</span>.props;</span><br><span class="line">            <span class="keyword">return</span> loading ? <span class="xml"><span class="tag">&lt;<span class="name">div</span>&gt;</span>Loading...<span class="tag">&lt;/<span class="name">div</span>&gt;</span></span> : <span class="xml"><span class="tag">&lt;<span class="name">WrappedComponent</span> &#123; <span class="attr">...props</span> <span class="attr">as</span> <span class="attr">P</span> &#125; /&gt;</span></span>;</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">export</span> <span class="keyword">default</span> HelloHOC(HelloClass);</span><br></pre></td></tr></table></figure>
<h4 id="2-2-4-Hooks组件"><a href="#2-2-4-Hooks组件" class="headerlink" title="2.2.4 Hooks组件"></a>2.2.4 Hooks组件</h4><figure class="highlight js"><table><tr><td class="code"><pre><span class="line"><span class="keyword">import</span> React, &#123; useState, useEffect &#125; <span class="keyword">from</span> <span class="string">'react'</span>;</span><br><span class="line"><span class="keyword">import</span> &#123; Button &#125; <span class="keyword">from</span> <span class="string">'antd'</span>;</span><br><span class="line"></span><br><span class="line">interface Greeting &#123;</span><br><span class="line">    name: string;</span><br><span class="line">    firstName: string;</span><br><span class="line">    lastName: string;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">const</span> HelloHooks = <span class="function">(<span class="params">props: Greeting</span>) =&gt;</span> &#123;</span><br><span class="line">    <span class="keyword">const</span> [count, setCount] = useState(<span class="number">0</span>);</span><br><span class="line">    <span class="keyword">const</span> [text, setText] = useState&lt;string | <span class="literal">null</span>&gt;(<span class="literal">null</span>);</span><br><span class="line"></span><br><span class="line">    useEffect(<span class="function"><span class="params">()</span> =&gt;</span> &#123;</span><br><span class="line">        <span class="keyword">if</span> (count &gt; <span class="number">5</span>) &#123;</span><br><span class="line">            setText(<span class="string">'休息一下'</span>);</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;, [count]);</span><br><span class="line"></span><br><span class="line">    <span class="keyword">return</span> (</span><br><span class="line">        &lt;&gt;</span><br><span class="line">            &lt;p&gt;你点击了 &#123;count&#125; 次 &#123;text&#125;&lt;<span class="regexp">/p&gt;</span></span><br><span class="line"><span class="regexp">            &lt;Button onClick=&#123;() =&gt; &#123;setCount(count + 1)&#125;&#125;&gt;</span></span><br><span class="line"><span class="regexp">                Hello &#123;props.name&#125;</span></span><br><span class="line"><span class="regexp">            &lt;/</span>Button&gt;</span><br><span class="line">        &lt;<span class="regexp">/&gt;</span></span><br><span class="line"><span class="regexp">    )</span></span><br><span class="line"><span class="regexp">&#125;</span></span><br><span class="line"><span class="regexp"></span></span><br><span class="line"><span class="regexp">HelloHooks.defaultProps = &#123;</span></span><br><span class="line"><span class="regexp">    firstName: '',</span></span><br><span class="line"><span class="regexp">    lastName: ''</span></span><br><span class="line"><span class="regexp">&#125;</span></span><br><span class="line"><span class="regexp"></span></span><br><span class="line"><span class="regexp">export default HelloHooks;</span></span><br></pre></td></tr></table></figure>
<h4 id="2-2-5-事件处理与数据请求"><a href="#2-2-5-事件处理与数据请求" class="headerlink" title="2.2.5 事件处理与数据请求"></a>2.2.5 事件处理与数据请求</h4><figure class="highlight js"><table><tr><td class="code"><pre><span class="line"><span class="keyword">import</span> React, &#123; Component, useState, useEffect &#125; <span class="keyword">from</span> <span class="string">'react'</span>;</span><br><span class="line"><span class="keyword">import</span> &#123; Form, Input, Select, Button &#125; <span class="keyword">from</span> <span class="string">'antd'</span>;</span><br><span class="line"><span class="keyword">import</span> &#123; FormComponentProps &#125; <span class="keyword">from</span> <span class="string">'antd/lib/form'</span>;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> &#123; <span class="keyword">get</span> &#125; from '../../utils/request';</span><br><span class="line">import &#123; GET_EMPLOYEE_URL &#125; <span class="keyword">from</span> <span class="string">'../../constants/urls'</span>;</span><br><span class="line"><span class="keyword">import</span> &#123; EmployeeRequest, EmployeeResponse &#125; <span class="keyword">from</span> <span class="string">'../../interface/employee'</span>;</span><br><span class="line"></span><br><span class="line"><span class="keyword">const</span> &#123; Option &#125; = Select;</span><br><span class="line"></span><br><span class="line">interface Props extends FormComponentProps &#123;</span><br><span class="line">    onDataChange(data: EmployeeResponse): <span class="keyword">void</span></span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">// Hooks version</span></span><br><span class="line"><span class="comment">// const QueryFormHooks = (props: Props) =&gt; &#123;</span></span><br><span class="line"><span class="comment">//     const [name, setName] = useState('');</span></span><br><span class="line"><span class="comment">//     const [departmentId, setDepartmentId] = useState&lt;number | undefined&gt;();</span></span><br><span class="line"></span><br><span class="line"><span class="comment">//     const handleNameChange = (e: React.FormEvent&lt;HTMLInputElement&gt;) =&gt; &#123;</span></span><br><span class="line"><span class="comment">//         setName(e.currentTarget.value)</span></span><br><span class="line"><span class="comment">//     &#125;</span></span><br><span class="line"></span><br><span class="line"><span class="comment">//     const handleDepartmentChange = (value: number) =&gt; &#123;</span></span><br><span class="line"><span class="comment">//         setDepartmentId(value)</span></span><br><span class="line"><span class="comment">//     &#125;</span></span><br><span class="line"></span><br><span class="line"><span class="comment">//     const handleSubmit = () =&gt; &#123;</span></span><br><span class="line"><span class="comment">//         queryEmployee(&#123;name, departmentId&#125;);</span></span><br><span class="line"><span class="comment">//     &#125;</span></span><br><span class="line"></span><br><span class="line"><span class="comment">//     const queryEmployee = (param: EmployeeRequest) =&gt; &#123;</span></span><br><span class="line"><span class="comment">//         get(GET_EMPLOYEE_URL, param).then(res =&gt; &#123;</span></span><br><span class="line"><span class="comment">//             props.onDataChange(res.data);</span></span><br><span class="line"><span class="comment">//         &#125;);</span></span><br><span class="line"><span class="comment">//     &#125;</span></span><br><span class="line"></span><br><span class="line"><span class="comment">//     useEffect(() =&gt; &#123;</span></span><br><span class="line"><span class="comment">//         queryEmployee(&#123;name, departmentId&#125;);</span></span><br><span class="line"><span class="comment">//     &#125;, [])</span></span><br><span class="line"></span><br><span class="line"><span class="comment">//     return (</span></span><br><span class="line"><span class="comment">//         &lt;&gt;</span></span><br><span class="line"><span class="comment">//             &lt;Form layout="inline"&gt;</span></span><br><span class="line"><span class="comment">//                 &lt;Form.Item&gt;</span></span><br><span class="line"><span class="comment">//                     &lt;Input</span></span><br><span class="line"><span class="comment">//                         placeholder="姓名"</span></span><br><span class="line"><span class="comment">//                         style=&#123;&#123; width: 120 &#125;&#125;</span></span><br><span class="line"><span class="comment">//                         allowClear</span></span><br><span class="line"><span class="comment">//                         value=&#123;name&#125;</span></span><br><span class="line"><span class="comment">//                         onChange=&#123;handleNameChange&#125;</span></span><br><span class="line"><span class="comment">//                     /&gt;</span></span><br><span class="line"><span class="comment">//                 &lt;/Form.Item&gt;</span></span><br><span class="line"><span class="comment">//                 &lt;Form.Item&gt;</span></span><br><span class="line"><span class="comment">//                 &lt;Select</span></span><br><span class="line"><span class="comment">//                     placeholder="部门"</span></span><br><span class="line"><span class="comment">//                     style=&#123;&#123; width: 120 &#125;&#125;</span></span><br><span class="line"><span class="comment">//                     allowClear</span></span><br><span class="line"><span class="comment">//                     value=&#123;departmentId&#125;</span></span><br><span class="line"><span class="comment">//                     onChange=&#123;handleDepartmentChange&#125;</span></span><br><span class="line"><span class="comment">//                 &gt;</span></span><br><span class="line"><span class="comment">//                     &lt;Option value=&#123;1&#125;&gt;技术部&lt;/Option&gt;</span></span><br><span class="line"><span class="comment">//                     &lt;Option value=&#123;2&#125;&gt;产品部&lt;/Option&gt;</span></span><br><span class="line"><span class="comment">//                     &lt;Option value=&#123;3&#125;&gt;市场部&lt;/Option&gt;</span></span><br><span class="line"><span class="comment">//                     &lt;Option value=&#123;4&#125;&gt;运营部&lt;/Option&gt;</span></span><br><span class="line"><span class="comment">//                 &lt;/Select&gt;</span></span><br><span class="line"><span class="comment">//                 &lt;/Form.Item&gt;</span></span><br><span class="line"><span class="comment">//                 &lt;Form.Item&gt;</span></span><br><span class="line"><span class="comment">//                     &lt;Button type="primary" onClick=&#123;handleSubmit&#125;&gt;查询&lt;/Button&gt;</span></span><br><span class="line"><span class="comment">//                 &lt;/Form.Item&gt;</span></span><br><span class="line"><span class="comment">//             &lt;/Form&gt;</span></span><br><span class="line"><span class="comment">//         &lt;/&gt;</span></span><br><span class="line"><span class="comment">//     )</span></span><br><span class="line"><span class="comment">// &#125;</span></span><br><span class="line"></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">QueryForm</span> <span class="keyword">extends</span> <span class="title">Component</span>&lt;<span class="title">Props</span>, <span class="title">EmployeeRequest</span>&gt; </span>&#123;</span><br><span class="line">    state: EmployeeRequest = &#123;</span><br><span class="line">        name: <span class="string">''</span>,</span><br><span class="line">        departmentId: <span class="literal">undefined</span></span><br><span class="line">    &#125;</span><br><span class="line">    handleNameChange = <span class="function">(<span class="params">e: React.FormEvent&lt;HTMLInputElement&gt;</span>) =&gt;</span> &#123;</span><br><span class="line">        <span class="keyword">this</span>.setState(&#123;</span><br><span class="line">            name: e.currentTarget.value</span><br><span class="line">        &#125;);</span><br><span class="line">    &#125;</span><br><span class="line">    handleDepartmentChange = <span class="function">(<span class="params">value: number</span>) =&gt;</span> &#123;</span><br><span class="line">        <span class="keyword">this</span>.setState(&#123;</span><br><span class="line">            departmentId: value</span><br><span class="line">        &#125;);</span><br><span class="line">    &#125;</span><br><span class="line">    handleSubmit = <span class="function"><span class="params">()</span> =&gt;</span> &#123;</span><br><span class="line">        <span class="keyword">this</span>.queryEmployee(<span class="keyword">this</span>.state);</span><br><span class="line">    &#125;</span><br><span class="line">    componentDidMount() &#123;</span><br><span class="line">        <span class="keyword">this</span>.queryEmployee(<span class="keyword">this</span>.state);</span><br><span class="line">    &#125;</span><br><span class="line">    queryEmployee(param: EmployeeRequest) &#123;</span><br><span class="line">        <span class="keyword">get</span>(GET_EMPLOYEE_URL, param).then(res =&gt; &#123;</span><br><span class="line">            <span class="keyword">this</span>.props.onDataChange(res.data);</span><br><span class="line">        &#125;);</span><br><span class="line">    &#125;</span><br><span class="line">    render() &#123;</span><br><span class="line">        <span class="keyword">return</span> (</span><br><span class="line">            &lt;Form layout=<span class="string">"inline"</span>&gt;</span><br><span class="line">                &lt;Form.Item&gt;</span><br><span class="line">                    &lt;Input</span><br><span class="line">                        placeholder=<span class="string">"姓名"</span></span><br><span class="line">                        style=&#123;&#123; <span class="attr">width</span>: <span class="number">120</span> &#125;&#125;</span><br><span class="line">                        allowClear</span><br><span class="line">                        value=&#123;<span class="keyword">this</span>.state.name&#125;</span><br><span class="line">                        onChange=&#123;<span class="keyword">this</span>.handleNameChange&#125;</span><br><span class="line">                    /&gt;</span><br><span class="line">                &lt;<span class="regexp">/Form.Item&gt;</span></span><br><span class="line"><span class="regexp">                &lt;Form.Item&gt;</span></span><br><span class="line"><span class="regexp">                &lt;Select</span></span><br><span class="line"><span class="regexp">                    placeholder="部门"</span></span><br><span class="line"><span class="regexp">                    style=&#123;&#123; width: 120 &#125;&#125;</span></span><br><span class="line"><span class="regexp">                    allowClear</span></span><br><span class="line"><span class="regexp">                    value=&#123;this.state.departmentId&#125;</span></span><br><span class="line"><span class="regexp">                    onChange=&#123;this.handleDepartmentChange&#125;</span></span><br><span class="line"><span class="regexp">                &gt;</span></span><br><span class="line"><span class="regexp">                    &lt;Option value=&#123;1&#125;&gt;技术部&lt;/</span>Option&gt;</span><br><span class="line">                    &lt;Option value=&#123;<span class="number">2</span>&#125;&gt;产品部&lt;<span class="regexp">/Option&gt;</span></span><br><span class="line"><span class="regexp">                    &lt;Option value=&#123;3&#125;&gt;市场部&lt;/</span>Option&gt;</span><br><span class="line">                    &lt;Option value=&#123;<span class="number">4</span>&#125;&gt;运营部&lt;<span class="regexp">/Option&gt;</span></span><br><span class="line"><span class="regexp">                &lt;/</span>Select&gt;</span><br><span class="line">                &lt;<span class="regexp">/Form.Item&gt;</span></span><br><span class="line"><span class="regexp">                &lt;Form.Item&gt;</span></span><br><span class="line"><span class="regexp">                    &lt;Button type="primary" onClick=&#123;this.handleSubmit&#125;&gt;查询&lt;/</span>Button&gt;</span><br><span class="line">                &lt;<span class="regexp">/Form.Item&gt;</span></span><br><span class="line"><span class="regexp">            &lt;/</span>Form&gt;</span><br><span class="line">        )</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">const</span> WrapQueryForm = Form.create&lt;Props&gt;(&#123;</span><br><span class="line">    name: <span class="string">'employee_query'</span></span><br><span class="line">&#125;)(QueryForm);</span><br><span class="line"></span><br><span class="line"><span class="keyword">export</span> <span class="keyword">default</span> WrapQueryForm;</span><br></pre></td></tr></table></figure>
<h4 id="2-2-6-列表渲染"><a href="#2-2-6-列表渲染" class="headerlink" title="2.2.6 列表渲染"></a>2.2.6 列表渲染</h4><figure class="highlight js"><table><tr><td class="code"><pre><span class="line"><span class="keyword">import</span> React, &#123; Component, useState &#125; <span class="keyword">from</span> <span class="string">'react'</span>;</span><br><span class="line"><span class="keyword">import</span> &#123; Table &#125; <span class="keyword">from</span> <span class="string">'antd'</span>;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> <span class="string">'./index.css'</span>;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> QueryForm <span class="keyword">from</span> <span class="string">'./QueryForm'</span>;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> &#123; employeeColumns &#125; <span class="keyword">from</span> <span class="string">'./colums'</span>;</span><br><span class="line"><span class="keyword">import</span> &#123; EmployeeResponse &#125; <span class="keyword">from</span> <span class="string">'../../interface/employee'</span>;</span><br><span class="line"></span><br><span class="line"><span class="comment">// Hooks version</span></span><br><span class="line"><span class="comment">// const Employee = () =&gt; &#123;</span></span><br><span class="line"><span class="comment">//     const [employee, setEmployee] = useState&lt;EmployeeResponse&gt;(undefined);</span></span><br><span class="line"></span><br><span class="line"><span class="comment">//     const getTotal = () =&gt; &#123;</span></span><br><span class="line"><span class="comment">//         let total: number;</span></span><br><span class="line"><span class="comment">//         if (typeof employee !== 'undefined') &#123;</span></span><br><span class="line"><span class="comment">//             total = employee.length</span></span><br><span class="line"><span class="comment">//         &#125; else &#123;</span></span><br><span class="line"><span class="comment">//             total = 0</span></span><br><span class="line"><span class="comment">//         &#125;</span></span><br><span class="line"><span class="comment">//         return &lt;p&gt;共 &#123;total&#125; 名员工&lt;/p&gt;</span></span><br><span class="line"><span class="comment">//     &#125;</span></span><br><span class="line"></span><br><span class="line"><span class="comment">//     return (</span></span><br><span class="line"><span class="comment">//         &lt;&gt;</span></span><br><span class="line"><span class="comment">//             &lt;QueryForm onDataChange=&#123;setEmployee&#125; /&gt;</span></span><br><span class="line"><span class="comment">//             &#123;/* &#123;getTotal()&#125; */&#125;</span></span><br><span class="line"><span class="comment">//             &lt;Table columns=&#123;employeeColumns&#125; dataSource=&#123;employee&#125; className="table" /&gt;</span></span><br><span class="line"><span class="comment">//         &lt;/&gt;</span></span><br><span class="line"><span class="comment">//     )</span></span><br><span class="line"><span class="comment">// &#125;</span></span><br><span class="line"></span><br><span class="line">interface State &#123;</span><br><span class="line">    employee: EmployeeResponse</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">Employee</span> <span class="keyword">extends</span> <span class="title">Component</span>&lt;</span>&#123;&#125;, State&gt; &#123;</span><br><span class="line">    state: State = &#123;</span><br><span class="line">        employee: <span class="literal">undefined</span></span><br><span class="line">    &#125;</span><br><span class="line">    setEmployee = <span class="function">(<span class="params">employee: EmployeeResponse</span>) =&gt;</span> &#123;</span><br><span class="line">        <span class="keyword">this</span>.setState(&#123;</span><br><span class="line">            employee</span><br><span class="line">        &#125;);</span><br><span class="line">    &#125;</span><br><span class="line">    getTotal() &#123;</span><br><span class="line">        <span class="keyword">let</span> total: number;</span><br><span class="line">        <span class="comment">// 类型保护</span></span><br><span class="line">        <span class="keyword">if</span> (<span class="keyword">typeof</span> <span class="keyword">this</span>.state.employee !== <span class="string">'undefined'</span>) &#123;</span><br><span class="line">            total = <span class="keyword">this</span>.state.employee.length</span><br><span class="line">        &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">            total = <span class="number">0</span></span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">return</span> <span class="xml"><span class="tag">&lt;<span class="name">p</span>&gt;</span>共 &#123;total&#125; 名员工<span class="tag">&lt;/<span class="name">p</span>&gt;</span></span></span><br><span class="line">    &#125;</span><br><span class="line">    render() &#123;</span><br><span class="line">        <span class="keyword">return</span> (</span><br><span class="line">            &lt;&gt;</span><br><span class="line">                &lt;QueryForm onDataChange=&#123;<span class="keyword">this</span>.setEmployee&#125; /&gt;</span><br><span class="line">                &#123;<span class="comment">/* &#123;this.getTotal()&#125; */</span>&#125;</span><br><span class="line">                &lt;Table columns=&#123;employeeColumns&#125; dataSource=&#123;<span class="keyword">this</span>.state.employee&#125; className=<span class="string">"table"</span> /&gt;</span><br><span class="line">            &lt;<span class="regexp">/&gt;</span></span><br><span class="line"><span class="regexp">        )</span></span><br><span class="line"><span class="regexp">    &#125;</span></span><br><span class="line"><span class="regexp">&#125;</span></span><br><span class="line"><span class="regexp"></span></span><br><span class="line"><span class="regexp">export default Employee;</span></span><br></pre></td></tr></table></figure>
<h4 id="2-2-7-Redux与类型"><a href="#2-2-7-Redux与类型" class="headerlink" title="2.2.7 Redux与类型"></a>2.2.7 Redux与类型</h4><blockquote>
<p>项目代码 <a href="https://github.com/poetries/typescript-in-action/tree/master/ts-redux" target="_blank" rel="noopener">https://github.com/poetries/typescript-in-action/tree/master/ts-redux</a></p>
</blockquote>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line"><span class="keyword">import</span> &#123; Dispatch &#125; <span class="keyword">from</span> <span class="string">'redux'</span>;</span><br><span class="line"><span class="keyword">import</span> _ <span class="keyword">from</span> <span class="string">'lodash'</span>;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> &#123; <span class="keyword">get</span>, post &#125; from '../../utils/request';</span><br><span class="line">import &#123; department, level &#125; <span class="keyword">from</span> <span class="string">'../../constants/options'</span>;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> &#123;</span><br><span class="line">    GET_EMPLOYEE_URL,</span><br><span class="line">    CREATE_EMPLOYEE_URL,</span><br><span class="line">    DELETE_EMPLOYEE_URL,</span><br><span class="line">    UPDATE_EMPLOYEE_URL</span><br><span class="line">&#125; <span class="keyword">from</span> <span class="string">'../../constants/urls'</span>;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> &#123;</span><br><span class="line">    GET_EMPLOYEE,</span><br><span class="line">    CREATE_EMPLOYEE,</span><br><span class="line">    DELETE_EMPLOYEE,</span><br><span class="line">    UPDATE_EMPLOYEE</span><br><span class="line">&#125; <span class="keyword">from</span> <span class="string">'../../constants/actions'</span>;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> &#123;</span><br><span class="line">    EmployeeInfo,</span><br><span class="line">    EmployeeRequest,</span><br><span class="line">    EmployeeResponse,</span><br><span class="line">    CreateRequest,</span><br><span class="line">    DeleteRequest,</span><br><span class="line">    UpdateRequest</span><br><span class="line">&#125; <span class="keyword">from</span> <span class="string">'../../interface/employee'</span>;</span><br><span class="line"></span><br><span class="line">type State = Readonly&lt;&#123;</span><br><span class="line">    employeeList: EmployeeResponse</span><br><span class="line">&#125;&gt;</span><br><span class="line"></span><br><span class="line">type Action = &#123;</span><br><span class="line">    type: string;</span><br><span class="line">    payload: any;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">const</span> initialState: State = &#123;</span><br><span class="line">    employeeList: <span class="literal">undefined</span></span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">export</span> <span class="function"><span class="keyword">function</span> <span class="title">getEmployee</span>(<span class="params">param: EmployeeRequest, callback: (</span>) =&gt; <span class="title">void</span>) </span>&#123;</span><br><span class="line">    <span class="keyword">return</span> <span class="function">(<span class="params">dispatch: Dispatch</span>) =&gt;</span> &#123;</span><br><span class="line">        <span class="keyword">get</span>(GET_EMPLOYEE_URL, param).then(res =&gt; &#123;</span><br><span class="line">            dispatch(&#123;</span><br><span class="line">                type: GET_EMPLOYEE,</span><br><span class="line">                payload: res.data</span><br><span class="line">            &#125;);</span><br><span class="line">            callback();</span><br><span class="line">        &#125;);</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">export</span> <span class="function"><span class="keyword">function</span> <span class="title">createEmployee</span>(<span class="params">param: CreateRequest, callback: (</span>) =&gt; <span class="title">void</span>) </span>&#123;</span><br><span class="line">    <span class="keyword">return</span> <span class="function">(<span class="params">dispatch: Dispatch</span>) =&gt;</span> &#123;</span><br><span class="line">        post(CREATE_EMPLOYEE_URL, param).then(<span class="function"><span class="params">res</span> =&gt;</span> &#123;</span><br><span class="line">            dispatch(&#123;</span><br><span class="line">                type: CREATE_EMPLOYEE,</span><br><span class="line">                payload: &#123;</span><br><span class="line">                    name: param.name,</span><br><span class="line">                    department: department[param.departmentId],</span><br><span class="line">                    departmentId: param.departmentId,</span><br><span class="line">                    hiredate: param.hiredate,</span><br><span class="line">                    level: level[param.levelId],</span><br><span class="line">                    levelId: param.levelId,</span><br><span class="line">                    ...res.data</span><br><span class="line">                &#125;</span><br><span class="line">            &#125;);</span><br><span class="line">            callback();</span><br><span class="line">        &#125;);</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">export</span> <span class="function"><span class="keyword">function</span> <span class="title">deleteEmployee</span>(<span class="params">param: DeleteRequest</span>) </span>&#123;</span><br><span class="line">    <span class="keyword">return</span> <span class="function">(<span class="params">dispatch: Dispatch</span>) =&gt;</span> &#123;</span><br><span class="line">        post(DELETE_EMPLOYEE_URL, param).then(<span class="function"><span class="params">res</span> =&gt;</span> &#123;</span><br><span class="line">            dispatch(&#123;</span><br><span class="line">                type: DELETE_EMPLOYEE,</span><br><span class="line">                payload: param.id</span><br><span class="line">            &#125;)</span><br><span class="line">        &#125;);</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">export</span> <span class="function"><span class="keyword">function</span> <span class="title">updateEmployee</span>(<span class="params">param: UpdateRequest, callback: (</span>) =&gt; <span class="title">void</span>) </span>&#123;</span><br><span class="line">    <span class="keyword">return</span> <span class="function">(<span class="params">dispatch: Dispatch</span>) =&gt;</span> &#123;</span><br><span class="line">        post(UPDATE_EMPLOYEE_URL, param).then(<span class="function"><span class="params">res</span> =&gt;</span> &#123;</span><br><span class="line">            dispatch(&#123;</span><br><span class="line">                type: UPDATE_EMPLOYEE,</span><br><span class="line">                payload: param</span><br><span class="line">            &#125;);</span><br><span class="line">            callback();</span><br><span class="line">        &#125;);</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">export</span> <span class="keyword">default</span> <span class="function"><span class="keyword">function</span>(<span class="params">state = initialState, action: Action</span>) </span>&#123;</span><br><span class="line">    <span class="keyword">switch</span> (action.type) &#123;</span><br><span class="line">        <span class="keyword">case</span> GET_EMPLOYEE:</span><br><span class="line">            <span class="keyword">return</span> &#123;</span><br><span class="line">                ...state,</span><br><span class="line">                employeeList: action.payload</span><br><span class="line">            &#125;</span><br><span class="line">        <span class="keyword">case</span> CREATE_EMPLOYEE:</span><br><span class="line">            <span class="keyword">let</span> newList = [action.payload, ...(state.employeeList <span class="keyword">as</span> EmployeeInfo[])]</span><br><span class="line">            <span class="keyword">return</span> &#123;</span><br><span class="line">                ...state,</span><br><span class="line">                employeeList: newList</span><br><span class="line">            &#125;</span><br><span class="line">        <span class="keyword">case</span> DELETE_EMPLOYEE:</span><br><span class="line">            <span class="keyword">let</span> reducedList = [...(state.employeeList <span class="keyword">as</span> EmployeeInfo[])];</span><br><span class="line">            _.remove(reducedList, (item: EmployeeInfo) =&gt; &#123;</span><br><span class="line">                <span class="keyword">return</span> item.id === action.payload</span><br><span class="line">            &#125;);</span><br><span class="line">            <span class="keyword">return</span> &#123;</span><br><span class="line">                ...state,</span><br><span class="line">                employeeList: reducedList</span><br><span class="line">            &#125;</span><br><span class="line">        <span class="keyword">case</span> UPDATE_EMPLOYEE:</span><br><span class="line">            <span class="keyword">let</span> updatedList = [...(state.employeeList <span class="keyword">as</span> EmployeeInfo[])];</span><br><span class="line">            <span class="keyword">let</span> item: UpdateRequest = action.payload;</span><br><span class="line">            <span class="keyword">let</span> index = _.findIndex(updatedList, &#123;</span><br><span class="line">                id: item.id</span><br><span class="line">            &#125;);</span><br><span class="line">            updatedList[index] = &#123;</span><br><span class="line">                id: item.id,</span><br><span class="line">                key: item.id,</span><br><span class="line">                name: item.name,</span><br><span class="line">                department: department[item.departmentId],</span><br><span class="line">                departmentId: item.departmentId,</span><br><span class="line">                hiredate: item.hiredate,</span><br><span class="line">                level: level[item.levelId],</span><br><span class="line">                levelId: item.levelId</span><br><span class="line">            &#125;</span><br><span class="line">            <span class="keyword">return</span> &#123;</span><br><span class="line">                ...state,</span><br><span class="line">                employeeList: updatedList</span><br><span class="line">            &#125;</span><br><span class="line">        <span class="keyword">default</span>:</span><br><span class="line">            <span class="keyword">return</span> state</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<h3 id="2-3-服务端使用Typescript"><a href="#2-3-服务端使用Typescript" class="headerlink" title="2.3 服务端使用Typescript"></a>2.3 服务端使用Typescript</h3><blockquote>
<p>项目地址 <a href="https://github.com/poetries/typescript-in-action/tree/master/ts-express" target="_blank" rel="noopener">https://github.com/poetries/typescript-in-action/tree/master/ts-express</a></p>
</blockquote>
<h2 id="三、Vue项目实践"><a href="#三、Vue项目实践" class="headerlink" title="三、Vue项目实践"></a>三、Vue项目实践</h2><blockquote>
<p>项目代码 <a href="https://github.com/poetries/typescript-in-action/tree/master/ts-vue" target="_blank" rel="noopener">https://github.com/poetries/typescript-in-action/tree/master/ts-vue</a></p>
</blockquote>
<blockquote>
<p>TS不能识别<code>.vue</code>文件，需要声明文件</p>
</blockquote>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line"><span class="comment">// vue-shims.d.ts</span></span><br><span class="line"></span><br><span class="line">declare <span class="built_in">module</span> <span class="string">'*.vue'</span> &#123;</span><br><span class="line">    <span class="keyword">import</span> Vue <span class="keyword">from</span> <span class="string">'vue'</span></span><br><span class="line">    <span class="keyword">export</span> <span class="keyword">default</span> Vue</span><br><span class="line">  &#125;</span><br></pre></td></tr></table></figure>
<blockquote>
<p><a href="https://github.com/poetries/poetries.github.io/edit/dev/source/_posts/ts-in-action.md" target="_blank" rel="noopener">原文地址</a></p>
</blockquote>
<h1 id="更多资料"><a href="#更多资料" class="headerlink" title="更多资料"></a>更多资料</h1><ul>
<li><a href="http://blog.poetries.top/ts-axios/chapter1/">TypeScript 从零实现 axios</a></li>
<li><a href="http://blog.poetries.top/2018/12/29/ts-intro-and-use-in-react/">Typescript基础及结合React实践(一)</a></li>
<li><a href="http://blog.poetries.top/2018/12/30/ts-summary/">Typescript总结篇（二）</a></li>
<li><a href="http://blog.poetries.top/2018/12/31/ts-react-template/">Typescript+React模板搭建（三）</a></li>
</ul>

      </div>
    
  </div>

</article>

<button class="assist-btn2 circle" id="assist_btn2" title="点亮屏幕" style="left: 27px; top: 152px;">
  <i class="iconfont" style="display:inline-block;color:red;width:20px;height:20px;">&#xe61d;</i>
</button>
<button class="assist-btn1 circle" id="assist_btn1" title="关闭屏幕亮度" style="left: 27px; top: 152px;">
  <i class="iconfont toc-title" style="display:inline-block;color:red;width:20px;height:20px;">&#xe61d;</i>
</button>


<script src="//cdn.bootcss.com/jquery/3.1.1/jquery.min.js"></script>	

<script src="https://my.openwrite.cn/js/readmore.js" type="text/javascript"></script>
<script>
  const btw = new BTWPlugin();
  btw.init({
    id: "container",
    blogId: "22699-1592137983091-414",
    name: "前端进阶之旅",
    qrcode: "https://poetries1.gitee.io/img-repo/2020/06/qrcode.jpg",
    keyword: "3a3b3c",
  });
</script>

<script type="text/javascript">

// white theme
var body = {color: "#555", background: "#000"};
var a_tag = {color: "#222"};
var header = { background: "#222"};
var logo_line_i = {background: "#222"};
// var post_code = {background: "#eee", color: "#222"};

function switch_theme() {
 $("body").css(body);
 $("a:not('.links-of-author-item a, .site-state-item a, .site-state-posts a, .feed-link a, .motion-element a, .post-tags a, .show-commit-cls a, #donate_board a')").css(a_tag);
 $(".header, .footer").css(header);
 $(".logo-line-before i, .logo-line-after i").css(logo_line_i);
 //$(".post code").css(post_code);
 $("#idhyt-surprise-ball #idhyt-surprise-ball-animation .drag").css(a_tag);
 $(".post-title-link, .posts-expand .post-meta, .post-comments-count, .disqus-comment-count, .post-category a, .post-nav-next a, .post-nav-item a").css(a_tag);
 
 // $("code").css({color: '#c5c8c6', background: '#1d1f21'});
 //$("#assist_btn1").hide(1500);
}

$(function () {
$("#assist_btn2").css("display","none");
 $("#assist_btn1").click(function() {
     switch_theme();
$("div#toc.toc-article").css({
 "background":"#eaeaea",
 "opacity":1
});
$(".toc-article ol").show();
$("#toc.toc-article .toc-title").css("color","#a98602");
$("#assist_btn1").css("display","none");
$("#assist_btn2").css("display","block");
 });
$("#assist_btn2").click(function() {
$("#assist_btn2").css("display","none");
$("#assist_btn1").css("display","block");
$("body").css("background","url(http://www.miaov.com/static/ie/images/news/bg.png)")
     $(".header, .footer").css("background","url(http://www.miaov.com/static/ie/images/news/bg.png)")
$(".toc-article ol").toggle(1000);
 });
});


//背景随机

var Y, O, E, L, B, C, T, z, N, S, A, I;
!function() {
var e = function() {
for (O.clearRect(0, 0, L, B), T = [{
x: 0,
y: .7 * B + C
}, {
x: 0,
y: .7 * B - C
}]; T[1].x < L + C;) t(T[0], T[1])
}, t = function(e, t) {
O.beginPath(), O.moveTo(e.x, e.y), O.lineTo(t.x, t.y);
var n = t.x + (2 * I() - .25) * C,
 r = a(t.y);
O.lineTo(n, r), O.closePath(), N -= S / -50, O.fillStyle = "#" + (127 * A(N) + 128 << 16 | 127 * A(N + S / 3) + 128 << 8 | 127 * A(N + S / 3 * 2) + 128).toString(16), O.fill(), T[0] = T[1], T[1] = {
 x: n,
 y: r
}
}, a = function n(e) {
var t = e + (2 * I() - 1.1) * C;
return t > B || t < 0 ? n(e) : t
};
Y = document.getElementById("evanyou"), O = Y.getContext("2d"), E = window.devicePixelRatio || 1, L = window.innerWidth, B = window.innerHeight, C = 90, z = Math, N = 0, S = 2 * z.PI, A = z.cos, I = z.random, Y.width = L * E, Y.height = B * E, O.scale(E, E), O.globalAlpha = .6, document.onclick = e, document.ontouchstart = e, e()
}()

   
$("#toc-eye").click(function(){
$("#toc.toc-article").toggle(1000);
});

</script>


   
  <div class="text-center donation">
    <div class="inner-donation">
      <span class="btn-donation">支持一下</span>
      <div class="donation-body">
        <div class="tip text-center">扫一扫，支持poetries</div>
        <ul>
        
          <li class="item">
            
              <span>微信扫一扫</span>
            
            <img src="/images/weixin.jpg" alt="">
          </li>
        
          <li class="item">
            
              <span>支付宝扫一扫</span>
            
            <img src="/images/zhifubao.jpg" alt="">
          </li>
        
        </ul>
      </div>
    </div>
  </div>


   
  <div class="box-prev-next clearfix">
    <a class="show pull-left" href="/2019/09/02/react-feature/">
        <i class="icon icon-angle-left"></i>
    </a>
    <a class="show pull-right" href="/2019/09/22/JavaScript-event-loop/">
        <i class="icon icon-angle-right"></i>
    </a>
  </div>




</div>


  <a id="backTop" class="back-top">
    <i class="icon-angle-up"></i>
  </a>




  <div class="modal" id="modal">
  <span id="cover" class="cover hide"></span>
  <div id="modal-dialog" class="modal-dialog hide-dialog">
    <div class="modal-header">
      <span id="close" class="btn-close">关闭</span>
    </div>
    <hr>
    <div class="modal-body">
      <ul class="list-toolbox">
        
          <li class="item-toolbox">
            <a
              class="CIRCLE"
              href="/archives/"
              rel="noopener noreferrer"
              target="_self"
              >
              博客
            </a>
          </li>
        
          <li class="item-toolbox">
            <a
              class="CIRCLE"
              href="/categories/"
              rel="noopener noreferrer"
              target="_self"
              >
              分类
            </a>
          </li>
        
          <li class="item-toolbox">
            <a
              class="CIRCLE"
              href="/tags/"
              rel="noopener noreferrer"
              target="_self"
              >
              标签
            </a>
          </li>
        
          <li class="item-toolbox">
            <a
              class="CIRCLE"
              href="/search/"
              rel="noopener noreferrer"
              target="_self"
              >
              搜索
            </a>
          </li>
        
          <li class="item-toolbox">
            <a
              class="CIRCLE"
              href="/link/"
              rel="noopener noreferrer"
              target="_self"
              >
              友链
            </a>
          </li>
        
          <li class="item-toolbox">
            <a
              class="CIRCLE"
              href="/about/"
              rel="noopener noreferrer"
              target="_self"
              >
              关于
            </a>
          </li>
        
      </ul>

    </div>
  </div>
</div>



  
      <div class="fexo-comments comments-post">
    

    

    
    

    

    
    

    

<!-- Gitalk评论插件通用代码 -->
<div id="gitalk-container"></div>

<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/gitalk@1/dist/gitalk.css">
<script src="https://cdn.jsdelivr.net/npm/gitalk@1/dist/gitalk.min.js"></script>
<script>
const gitalk = new Gitalk({
  clientID: '5567a2c4abb858009d96',
  clientSecret: 'b9039ec056cf5c2346b3cdb63308a28c163f91e5',
  repo: 'poetries.github.io',
  owner: 'poetries',
  // 在这里设置一下截取前50个字符串, 这是因为 github 对 label 的长度有了要求, 如果超过
  // 50个字符串则会报错.
  // id: location.pathname.split('/').pop().substring(0, 49),
  id: location.pathname,
  admin: ['poetries'],
  // facebook-like distraction free mode
  distractionFreeMode: false
})
gitalk.render('gitalk-container')
</script>
<!-- Gitalk代码结束 -->



  </div>

  

  <script type="text/javascript">
  function loadScript(url, callback) {
    var script = document.createElement('script')
    script.type = 'text/javascript';

    if (script.readyState) { //IE
      script.onreadystatechange = function() {
        if (script.readyState == 'loaded' ||
          script.readyState == 'complete') {
          script.onreadystatechange = null;
          callback();
        }
      };
    } else { //Others
      script.onload = function() {
        callback();
      };
    }

    script.src = url;
    document.getElementsByTagName('head')[0].appendChild(script);
  }

  window.onload = function() {
    loadScript('/js/bundle.js?235683', function() {
      // load success
    });
  }
</script>


  <!-- 页面点击小红心 -->
  <script type="text/javascript" src="/js/clicklove.js"></script>
 
  
</body>
</html>
